Cannot read property 'shift' of undefined

I am making a level where there is a queue of items the player has to dequeue at the right time.
Currently the queue of sprites displays normally and the error comes up when I press the spacebar to dequeue an item.

When I log the queue is displays as normal, an array of QueueSprite objects, however when I trigger the function to dequeue an item when spacebar is pressed, it comes up with an error.

image

Here is some of my code related to the issue:

class Level2 extends Phaser.Scene {
constructor() {
	super("level2");
}
pipePositions = [100, 200, 300, 400, 500, 600, 700, 800];
queue = [];
choices = ['tetromino1', 'junk'];
score = 0;
lives = 3;
timeLeft;
minutes;
seconds;
create() {
	endgame = false;
	this.score = 0;
	this.lives = 3;
	this.queue = [];
	//pipe
	this.pipeBg = this.add.sprite(10, 520, 'pipe').setOrigin(0, 0);
	//initial queue
	for(var i in this.pipePositions) {
		this.sprite = new QueueSprite(
			this,
			this.pipePositions[i], 
			585,
			(this.choices[Math.floor(Math.random() * this.choices.length)]),
			Phaser.Math.Between(0, 31)
			);
		if (this.sprite.texture == 'tetromino1'){
			this.sprite.setTexture("tetromino1", Phaser.Math.Between(0, 31));
		}
		else if (this.sprite.texture == 'junk'){
			this.sprite.setTexture("junk", Phaser.Math.Between(0, 5));
		}
		this.queue.push(this.sprite);
	  }
	console.log(this.queue);
	//dequeueing using keyup
	this.input.keyboard.on('keyup_SPACE', function (event) {

		console.log('Hello from the Space Bar!');
		console.log(this.queue);

		// console.log(this.queue.length);
		var removed = this.queue.shift();
		// console.log(removed.key);
		if ((removed.texture.key=='tetromino')/*&& (overlap == true)*/){
			console.log("tetromino sent");
			// counterVal += 10;
			// self.counter.updateScore(counterVal);
		} else if ((removed.texture.key=='junk') /*&& (overlap == true)*/){
			console.log("junk sent");
			// counterVal -= 5;
			// self.counter.updateScore(counterVal);
		}
		removed.destroy();
		this.queue.push(new QueueSprite(
			this,
			this.pipePositions[i], 
			585,
			(this.choices[Math.floor(Math.random() * this.choices.length)]),
			Phaser.Math.Between(0, 31)));
		// console.log(q,xPositions);
		updatePositions(this.queue,this.pipePositions);

	});
            updatePositions(elementArray, posArray){
	    for (var i=0;elementArray.length;i++){
	      // console.log(i)
	      elementArray[i].position.x = posArray[i];
	}
  }
}

I realise this is probably related to where I bind this but I can’t for the life of me figure out where I’ve gone wrong, as this.queue works fine elsewhere.

Hey PandaJam, you were absolutely correct in stating that it’s how you bound this to the function.

You can fix this one of two ways. The first way is to set the keyboard’s listener’s context to this, by passing it in as the third parameter like so:

this.input.keyboard.on('keyup_SPACE', function (event) {
    //Your function code.
}, this); //The important part

Or, my favorite, you can use a lambda expression, like so:

this.input.keyboard.on('keyup_SPACE', (event)=>{
    //Your function code.
}); 
1 Like

That worked like a charm!
I do have another function inside that, which seems to be having a similar issue.

image
Funnily enough, it works fine on the surface, but the console shows errors…

this.input.keyboard.on('keyup_SPACE', function (event) {

		console.log('Hello from the Space Bar!');
		console.log(this.queue);

		// console.log(this.queue.length);
		var removed = this.queue.shift();
		// console.log(removed.key);
		if ((removed.texture.key=='tetromino')/*&& (overlap == true)*/){
			console.log("tetromino sent");
		} else if ((removed.texture.key=='junk') /*&& (overlap == true)*/){
			console.log("junk sent");
		}
		
		removed.destroy();
		this.queue.push(new QueueSprite(
			this,
			this.pipePositions[i], 
			585,
			(this.choices[Math.floor(Math.random() * this.choices.length)]),
			Phaser.Math.Between(0, 31)));
		// console.log(q,xPositions);
		this.updatePositions(this.queue,this.pipePositions);

	}, this); // added the binding here

updatePositions(elementArray, posArray){
		for (var i=0;elementArray.length;i++){
		  // console.log(i)
		  elementArray[i].x = posArray[i];
		}
	}

I’d imagine that error is due to your for loop within your updatePositions method. It looks like you forgot to specify while i is less than the elementArray length.

Try changing:

updatePositions(elementArray, posArray){
    for (var i=0;elementArray.length;i++){
        // console.log(i)
        elementArray[i].position.x = posArray[i];
    }
}

to:

updatePositions(elementArray, posArray){
    for (var i = 0; i < elementArray.length; i++){
        // console.log(i)
        elementArray[i].position.x = posArray[i];
    }
}
1 Like

Yes! That worked perfectly! Thank you so much!