I'm very new to Phaser 3 and I've been trying to create an instance where the player sprite collides with a game object that takes the player to another map. Right now I'm trying to make the player change scenes from house 1 to house 2, but when I move the player sprite over the game object nothing happens. No errors come up telling me something isn't defined or anything. It's as if the trigger for changing the scene never existed.
Here's the Player.js file
export default class Player {
constructor(scene, x, y) {
this.scene = scene;
const anims = scene.anims;
anims.create({
key: 'turn1',
frames: [ { key: 'dude', frame: 32 } ],
frameRate: 20
});
anims.create({
key: 'rdown',
frames: anims.generateFrameNumbers('dude', { start: 0, end: 7 }),
frameRate: 16,
repeat: -1
});
anims.create({
key: 'rright',
frames: anims.generateFrameNumbers('dude', { frames: [ 8, 9, 10, 11, 12, 13, 14, 15 ] }),
frameRate: 16,
repeat: -1
});
anims.create({
key: 'rup',
frames: anims.generateFrameNumbers('dude', { frames: [ 16, 17, 18, 19, 20, 21, 21, 23 ] }),
frameRate: 16,
repeat: -1
});
anims.create({
key: 'rleft',
frames: anims.generateFrameNumbers('dude', { frames: [ 24, 25, 26, 27, 28, 29, 30, 31 ] }),
frameRate: 16,
repeat: -1
});
this.sprite = scene.physics.add.sprite(x, y, "dude", 0).setSize(16, 16).setOffset(0, 8);
this.sprite.anims.play("rdown");
this.gamepad = scene.input.gamepad.once('down', function (pad, button, index) {
this.gamepad = pad;
}, this);
}
update() {
const gamepad = this.gamepad;
const sprite = this.sprite;
const speed = 90;
const prevVelocity = sprite.body.velocity.clone();
sprite.body.setVelocity(0);
if (gamepad.right && gamepad.up) {
sprite.body.setVelocityX(speed);
sprite.body.setVelocityY(-speed);
} else if (gamepad.right && gamepad.down) {
sprite.body.setVelocityX(speed);
sprite.body.setVelocityY(speed);
} else if (gamepad.left && gamepad.up) {
sprite.body.setVelocityX(-speed);
sprite.body.setVelocityY(-speed);
} else if (gamepad.left && gamepad.down) {
sprite.body.setVelocityX(-speed);
sprite.body.setVelocityY(speed);
} else if (gamepad.left) {
sprite.body.setVelocityX(-speed);
} else if (gamepad.right) {
sprite.body.setVelocityX(speed);
} else if (gamepad.up) {
sprite.body.setVelocityY(-speed);
} else if (gamepad.down) {
sprite.body.setVelocityY(speed);
}
sprite.body.velocity.normalize().scale(speed);
if (gamepad.left) {
sprite.anims.play("rleft", true);
} else if (gamepad.left && gamepad.down) {
sprite.anims.play("rleft", true);
} else if (gamepad.left && gamepad.up) {
sprite.anims.play("rleft", true);
} else if (gamepad.right && gamepad.down) {
sprite.anims.play("rright", true);
} else if (gamepad.right && gamepad.up) {
sprite.anims.play("rright", true);
} else if (gamepad.up) {
sprite.anims.play("rup", true);
} else if (gamepad.right) {
sprite.anims.play("rright", true);
} else if (gamepad.down) {
sprite.anims.play("rdown", true);
} else {
sprite.stopOnFrame(sprite.anims.currentAnim.getFrameAt(0))
}
}
}
Here's the TestLevel.js file
import Player from "./Player.js";
import TestRoom2 from "./TestRoom2.js";
export default class TestRoom extends Phaser.Scene {
map;
player;
constructor() {
super()
}
text;
preload() {
this.load.image('tiles', 'assets/tilemaps/tiles/house1.png');
this.load.spritesheet('dude', 'assets/images/link.png', { frameWidth: 16, frameHeight: 24 });
this.load.tilemapTiledJSON('map', 'assets/tilemaps/maps/TestRoom.json');
this.load.image('exit', 'assets/tilemaps/tiles/exit.png');
}
create()
{
this.map = this.make.tilemap({ key: 'map' });
this.map.landscape = this.map.addTilesetImage('house', 'tiles');
this.map.createLayer("ground", [this.map.landscape], 0, 0);
this.player = new Player(this, 128, 112);
this.map.createLayer("above", [this.map.landscape], 0, 0);
this.cameras.main.setSize(256,224);
this.cameras.main.setBounds(0, 0, this.map.widthInPixels, this.map.heightInPixels);
this.cameras.main.startFollow(this.player.sprite);
this.cameras.main.setDeadzone(4,4);
this.exited = this.physics.add.sprite(112, 220, 'exit').setOrigin(0,0);
this.exitBox= this.physics.add.group({
key: 'exit'});
this.physics.add.collider(this.player, this.exitBox, function(player, exitBox) { this.scene.start('TestRoom2')});
}
update() {
this.player.update();
this.physics.collide(this.player, this.exitBox, function(player, exitBox) { this.scene.start('TestRoom2')});
}
}
The other map is the same, but with TestRoom replacing TestRoom2.
Here's the main scene that has the game config
import TestRoom from "./TestRoom.js";
import TestRoom2 from "./TestRoom2.js";
var config = {
type: Phaser.AUTO,
width: 256,
height: 224,
backgroundColor: '#000000',
pixelArt: true,
input: {
gamepad: true
},
physics: {
default: 'arcade',
arcade: {
gravity: { y: 0 },
debug: true
}
},
scene: TestRoom, TestRoom2
};
var game = new Phaser.Game(config);
Everything works. The only thing that doesn't is initiating the scene change.
What can I do to fix this?
First the config
is not 100% correct, all scenes have to be in an array ( or be added later manually ). Here you are missing square brackets [, ]
var config = {
type: Phaser.AUTO,
width: 256,
height: 224,
...
scene: [TestRoom, TestRoom2] // <-- missing brackets
};
Next, you can remove the following line, from the update
function, the collider
in the create
function is enough:
// remove this line from "update" function
this.physics.collide(this.player, this.exitBox, function(player, exitBox) { this.scene.start('TestRoom2')});
In the create
function, alter the following line to pass the context for the callback function (Link to documentation):
// added to parameters ( for details check documnetation )
this.physics.add.collider(this.player, this.exitBox, function(player, exitBox) { this.scene.start('TestRoom2')}, null, this);
Or use a arrow function (link to documentation):
// altered with to an arrow function
this.physics.add.collider(this.player, this.exitBox, (player, exitBox) => { this.scene.start('TestRoom2')});
I think this should cover all errors I could find, by reading the code.
btw.: check the browser console for errors, this can help finding and solving problems.
Update:
I think the line in the create
function should be exited
instead of exitBox
, since a empty group will never collide with the player:
this.physics.add.collider(this.player, this.exited, (player, exited) => { this.scene.start('TestRoom2')});
You could checkout the example of this answer to see a short working example of player/scene switching.
Update:
Based on the comments, you can fixe th issue of not colliding, is using the following line of code.
The reason is that the Player
class is not a Phaser GameObject, but a simple javascript class. You can use the sprite
property of the Player
class.
this.physics.add.collider(this.player.sprite, this.exited, (player, exited) => { this.scene.start('TestRoom2')});