Cannot read property 'delayedCall' of undefined

Hello!

I am new here so forgive me if this has been covered, and I am a novice at best with my javascript, but here’s whats happening:

Everything loads fine except for the animations of my sprite/gameobject Metrus, throwing the error:

Cannot read property ‘delayedCall’ of undefined (line 104) in chrome.
I am running phaser v3.

var width = window.innerWidth;
var height = window.innerHeight;

var cursorPosition; 
var cursorPos;
var clickCallback;
var thisTile;
var unitData;
var thisUnit;

var directions = {
west: { offset: 92, x: -2, y: 0, opposite: 'east' },
northWest: { offset: 138, x: -2, y: -1, opposite: 'southEast' },
north: { offset: 184, x: 0, y: -2, opposite: 'south' },
northEast: { offset: 230, x: 2, y: -1, opposite: 'southWest' },
east: { offset: 276, x: 2, y: 0, opposite: 'west' },
southEast: { offset: 322, x: 2, y: 1, opposite: 'northWest' },
south: { offset: 0, x: 0, y: 2, opposite: 'north' },
southWest: { offset: 46, x: -2, y: 1, opposite: 'northEast' }
};

var anims = {
walk: {
    startFrame: 0,
    endFrame: 22,
    speed: 0.1
},
attack: {
    startFrame: 23,
    endFrame: 45,
    speed: 0.1
}

};

var metruss = [];

var tileWidthHalf;
var tileHeightHalf;

var d = 0;

var scene;

//METRUS GAME OBJECT
class Metrus extends Phaser.GameObjects.Image {
constructor(scene, x, y, motion, direction, distance) {
    super(scene, x, y, 'metrustotalsprite', direction.offset);

    this.startX = x;
    this.startY = y;
    this.distance = distance;

    this.motion = motion;
    this.anim = anims[motion];
    this.direction = directions[direction];
    this.speed = 0.15;
    this.f = this.anim.startFrame;
	this.setScale(0.4);
	this.setOrigin(0.5, 0.75);

    this.depth = y + 64;

    scene.time.delayedCall(this.anim.speed * 1000, this.changeFrame, [], this);
}

changeFrame ()
{
    this.f++;

    var delay = this.anim.speed;

    if (this.f === this.anim.endFrame)
    {
        switch (this.motion)
        {
            case 'walk':
                this.f = this.anim.startFrame;
                this.frame = this.texture.get(this.direction.offset + this.f);
                scene.time.delayedCall(delay * 1000, this.changeFrame, [], this);
                break;

            case 'attack':
                delay = Math.random() * 2;
                scene.time.delayedCall(delay * 1000, this.resetAnimation, [], this);
                break;

            case 'idle':
                delay = 0.5 + Math.random();
                scene.time.delayedCall(delay * 1000, this.resetAnimation, [], this);
                break;

            case 'die':
                delay = 6 + Math.random() * 6;
                scene.time.delayedCall(delay * 1000, this.resetAnimation, [], this);
                break;
        }
    }
    else
    {
        this.frame = this.texture.get(this.direction.offset + this.f);
		scene.time.delayedCall(delay * 1000, this.changeFrame, [], this);
		//console.log(scene.time.delayedCall(delay * 1000, this.changeFrame, [], this));
    }
}

resetAnimation ()
{
    this.f = this.anim.startFrame;

    this.frame = this.texture.get(this.direction.offset + this.f);

    scene.time.delayedCall(this.anim.speed * 1000, this.changeFrame, [], this);
}

update ()
{
    if (this.motion === 'walk')
    {
        this.x += this.direction.x * this.speed;

        if (this.direction.y !== 0)
        {
            this.y += this.direction.y * this.speed;
            this.depth = this.y + 64;
        }

        //  Walked far enough?
        if (Phaser.Math.Distance.Between(this.startX, this.startY, this.x, this.y) >= this.distance)
        {
            this.direction = directions[this.direction.opposite];
            this.f = this.anim.startFrame;
            this.frame = this.texture.get(this.direction.offset + this.f);
            this.startX = this.x;
            this.startY = this.y;
        }
    }
}
}

class GameScene extends Phaser.Scene {

constructor() {
	super({key: 'GameScene'})	
}

preload () {
	scene = GameScene;
	
	this.load.image('stars', '../assets/backgrounds/stars.png');
		
	//UI SPRITESHEETS
	this.load.spritesheet('selected', '../assets/ui/selected.png', {frameWidth: 128, frameHeight: 128 });
	
	//TERRAIN SPRITESHEETS
	this.load.spritesheet('grasssprite', '../assets/terrain/grassworld/grasssprite.png', {frameWidth: 128, frameHeight: 128 });
	this.load.spritesheet('watersprite', '../assets/terrain/grassworld/watersprite.png', {frameWidth: 128, frameHeight: 128 });
	this.load.spritesheet('flatsprite', '../assets/terrain/grassworld/flatsprite.png', {frameWidth: 128, frameHeight: 128 });
	this.load.spritesheet('obstacles', '../assets/terrain/grassworld/obstacles.png', {frameWidth: 128, frameHeight: 128 });
	
	//UNIT SPRITESHEETS
	
	//CIMEX METRUS WALK
	this.load.spritesheet('metruswalknorth', '../assets/cimex/metrus/walk/walknorth.png', {frameWidth: 300, frameHeight: 300 });
	this.load.spritesheet('metruswalknortheast', '../assets/cimex/metrus/walk/walknortheast.png', {frameWidth: 300, frameHeight: 300 });
	this.load.spritesheet('metruswalkeast', '../assets/cimex/metrus/walk/walkeast.png', {frameWidth: 300, frameHeight: 300 });
	this.load.spritesheet('metruswalksoutheast', '../assets/cimex/metrus/walk/walksoutheast.png', {frameWidth: 300, frameHeight: 300 });
	this.load.spritesheet('metruswalksouth', '../assets/cimex/metrus/walk/walksouth.png', {frameWidth: 300, frameHeight: 300 });
	this.load.spritesheet('metruswalksouthwest', '../assets/cimex/metrus/walk/walksouthwest.png', {frameWidth: 300, frameHeight: 300 });
	this.load.spritesheet('metruswalkwest', '../assets/cimex/metrus/walk/walkwest.png', {frameWidth: 300, frameHeight: 300 });
	this.load.spritesheet('metruswalknorthwest', '../assets/cimex/metrus/walk/walknorthwest.png', {frameWidth: 300, frameHeight: 300 });
	
	this.load.spritesheet('metrustotalsprite', '../assets/cimex/metrus/metrustotalsprite.png', {frameWidth: 300, frameHeight: 300 });

	this.time.advancedTiming = true;


}


create () {
	//scene = GameScene;
	
	this.background = this.add.image(0,0, 'stars');
	this.background.setOrigin(0,0);
	this.background.displayWidth=game.config.width*1;
	this.background.displayHeight=game.config.height*1;
	this.background.setScrollFactor(0)
	this.background.fixedToCamera = true;
	
	var camWidth = game.config.width;
	var camHeight = game.config.Height;
	
    // SPAWN TILES FROM THE LEVELDATA
    this.spawnTiles();
	
	function unitData(callback){

		$.ajax({
			  type: 'GET',
			global: true, 
			  dataType: "json",
			  url:'../includes/units.php',
			contentType: 'application/json',
			  success: callback 
		});
		
	}
	
	unitData(result => {
		
	const tileWidthHalf = tileWidth / 2;
	const tileHeightHalf = tileHeight / 2;
	
	const centerX = mapWidth * tileWidthHalf;
	const centerY = 64;
	
	for (var i = 0; i < levelData.length; i++)
	{
		for (var j = 0; j < levelData[0].length; j++)
		{
			
			const tx = (j - i) * tileWidthHalf
			const ty = (j + i) * tileHeightHalf
			
			for (var z = 0; z < result.unitId.length; z++)
			{
			var unitX = result.unitX[z];
			var unitY = result.unitY[z];
				
			var unitType = result.unitType[z];
			var unitId = result.unitId[z];
			var unitAction = result.unitAction[z];
			var unitSprite = '' + unitType + '' + unitAction;
				
				if (unitX == i)
				{
					if (unitY == j) 
					{
					
					thisUnit = metruss.push(this.add.existing(new Metrus(this, centerX + tx, centerY + ty, 'walk', 'east', 100)));
					this.cameras.main.centerOn(centerX + tx, centerY + ty);

					}
				}
				
			}
			
		}
	}

	});
		

	



	
	
}


update () {
	
	//scene = GameScene;
	
	var cam = this.cameras.main; 
	this.cameras.main.setBounds(0, 0, mapWidth*tileWidth, mapWidth*tileHeight);
	cam.setZoom(1);

	
	
    const controlConfig = {
        camera: this.cameras.main,
        acceleration: 0.06,
        drag: 0.1,
        maxSpeed: 0
    };

    this.controls = new Phaser.Cameras.Controls.SmoothedKeyControl(controlConfig);
	
	this.input.on('pointermove', function (p) {
		if (!p.isDown) return;

		cam.scrollX -= (p.x - p.prevPosition.x) / 128;
		cam.scrollY -= (p.y - p.prevPosition.y) / 128;
		  
	});
	
	metruss.forEach(function (metrus) {
        metrus.update();
    }); 


}


render () {
    //this.debug.text(mapWidth + ' - ' + levelData, 2, 36, "#ffffff");
    this.debug.text(this.time.fps || '--', 2, 14, "#a7aebe");
}


spawnTiles (thisTile) {
	
	//scene = GameScene;
	
	var gameWidth = game.config.width;
	var gameHeight = game.config.height;
	
	const tileWidthHalf = tileWidth / 2;
	const tileHeightHalf = tileHeight / 2;
	
	const centerX = mapWidth * tileWidthHalf;
	const centerY = 64;
	
	var tileGroup = this.add.group();
 
	for (var i = 0; i < levelData.length; i++)
	{
		for (var j = 0; j < levelData[0].length; j++)
		{
			tileType=levelData[i][j];
			
			var tile = new Phaser.Geom.Point(i,j);
			
			

			const tx = (j - i) * tileWidthHalf
			const ty = (j + i) * tileHeightHalf
			
			//DEFINE TILE TYPES
			
			//GRASS0
			if (tileType==0)
			{
			thisTile = this.add.sprite(centerX + tx, centerY + ty, 'flatsprite',0);
			thisTile.depth = centerY + ty;
			thisTile.isWalkable = true; 
			tileGroup.add(thisTile);	
			}
			
			//GRASS1
			if (tileType==1)
			{
			thisTile = this.add.sprite(centerX + tx, centerY + ty, 'grasssprite',1);
			thisTile.depth = centerY + ty;
			tileGroup.add(thisTile);
			}
			
			//GRASS2
			if (tileType==2)
			{
			thisTile = this.add.sprite(centerX + tx, centerY + ty, 'grasssprite',2);
			thisTile.depth = centerY + ty;
			tileGroup.add(thisTile);
			}
			
			//GRASS3
			if (tileType==3)
			{
			thisTile = this.add.sprite(centerX + tx, centerY + ty, 'grasssprite',3);
			thisTile.depth = centerY + ty;
			tileGroup.add(thisTile);
			}
			
			//GRASS4
			if (tileType==4)
			{
			thisTile = this.add.sprite(centerX + tx, centerY + ty, 'grasssprite',4);
			thisTile.depth = centerY + ty
			tileGroup.add(thisTile); 
			}
			
			//GRASS5
			if (tileType==5)
			{
			thisTile = this.add.sprite(centerX + tx, centerY + ty, 'grasssprite',5);
			thisTile.depth = centerY + ty
			tileGroup.add(thisTile);
			}
						
			//GRASS6
			if (tileType==6)
			{
			thisTile = this.add.sprite(centerX + tx, centerY + ty, 'grasssprite',6);
			thisTile.depth = centerY + ty
			tileGroup.add(thisTile);  
			}
			
			//GRASS7
			if (tileType==7)
			{
			thisTile = this.add.sprite(centerX + tx, centerY + ty, 'grasssprite',7);
			thisTile.depth = centerY + ty
			tileGroup.add(thisTile);
			}
			
			//GRASS8
			if (tileType==8)
			{
			thisTile = this.add.sprite(centerX + tx, centerY + ty, 'grasssprite',8);
			thisTile.depth = centerY + ty
			tileGroup.add(thisTile);
			}
			
			//WATER
			if (tileType==9)
			{
			thisTile = this.add.sprite(centerX + tx, centerY + ty, 'flatsprite',5);
			thisTile.depth = centerY + ty
			tileGroup.add(thisTile);
			}	

			//WATER NORTHEAST
			if (tileType==10)
			{
			thisTile = this.add.sprite(centerX + tx, centerY + ty, 'watersprite',27);
			thisTile.depth = centerY + ty
			tileGroup.add(thisTile);
			}
			
			//WATER EAST
			if (tileType==11)
			{
			thisTile = this.add.sprite(centerX + tx, centerY + ty, 'watersprite',14);
			thisTile.depth = centerY + ty
			tileGroup.add(thisTile);
			}
			
			//WATER SOUTHEAST
			if (tileType==12)
			{
			thisTile = this.add.sprite(centerX + tx, centerY + ty, 'watersprite',25);
			thisTile.depth = centerY + ty
			tileGroup.add(thisTile);
			}
			
			//WATER SOUTH
			if (tileType==13)
			{
			thisTile = this.add.sprite(centerX + tx, centerY + ty, 'watersprite',17);
			thisTile.depth = centerY + ty
			tileGroup.add(thisTile);
			}
			
			//WATER SOUTHWEST
			if (tileType==14)
			{
			thisTile = this.add.sprite(centerX + tx, centerY + ty, 'watersprite',24);
			thisTile.depth = centerY + ty
			tileGroup.add(thisTile);               
			}
			
			//WATER WEST
			if (tileType==15)
			{
			thisTile = this.add.sprite(centerX + tx, centerY + ty, 'watersprite',15);
			thisTile.depth = centerY + ty
			tileGroup.add(thisTile);
			}
			
			//WATER NORTHWEST
			if (tileType==16)
			{
			thisTile = this.add.sprite(centerX + tx, centerY + ty, 'watersprite',26);
			thisTile.depth = centerY + ty
			tileGroup.add(thisTile);
			}

			//WATER NORTH
			if (tileType==17)
			{
			thisTile = this.add.sprite(centerX + tx, centerY + ty, 'watersprite',16);
			thisTile.depth = centerY + ty
			tileGroup.add(thisTile);
			}	
			
			//WATER EAST CORNER TIP
			if (tileType==18)
			{
			thisTile = this.add.sprite(centerX + tx, centerY + ty, 'watersprite',11);
			thisTile.depth = centerY + ty
			tileGroup.add(thisTile);
			}	
			
			//WATER SOUTH CORNER TIP
			if (tileType==19)
			{
			thisTile = this.add.sprite(centerX + tx, centerY + ty, 'watersprite',1);
			thisTile.depth = centerY + ty
			tileGroup.add(thisTile);
			}
			
			//WATER WEST CORNER TIP
			if (tileType==20)
			{
			thisTile = this.add.sprite(centerX + tx, centerY + ty, 'watersprite',10);
			thisTile.depth = centerY + ty
			tileGroup.add(thisTile);
			}
			
			//WATER NORTH CORNER TIP
			if (tileType==21)
			{
			thisTile = this.add.sprite(centerX + tx, centerY + ty, 'watersprite',0);
			thisTile.depth = centerY + ty
			tileGroup.add(thisTile);
			}
			
			//TREE OBSTACLE
			if (tileType==22)
			{
			thisTile = this.add.sprite(centerX + tx, centerY + ty, 'obstacles',0);
			thisTile.depth = centerY + ty
			tileGroup.add(thisTile);
			}
			
			//SHRUB OBSTACLE
			if (tileType==23)
			{
			thisTile = this.add.sprite(centerX + tx, centerY + ty, 'obstacles',1);
			thisTile.depth = centerY + ty
			tileGroup.add(thisTile);
			}
			
			//PONG PLANT OBSTACLE
			if (tileType==24)
			{
			thisTile = this.add.sprite(centerX + tx, centerY + ty, 'obstacles',2);
			thisTile.depth = centerY + ty
			tileGroup.add(thisTile);
			}

			//SMALL POND OBSTACLE
			if (tileType==25)
			{
			thisTile = this.add.sprite(centerX + tx, centerY + ty, 'obstacles',3);
			thisTile.depth = centerY + ty
			tileGroup.add(thisTile); 
			}	
			
			
				
			
		}
	}
	
}	

}

I guess line 104 is somewhere in changeFrame()?
scene probably doesn’t point to the actual scene.
Dangerous stuff having a global named scene, in the Metrus constructor you’re actually shadowing scene (using the passed argument, also called scene).