I’m making a top down game in Phaser 3.60.0 and I have everything coded to run on arcade physics. The only thing I need the matter physics engine for is sloped tiles used for diagonal walls.
Here are screenshots of what I have.
I haven’t figured out a way to have the two collide properly. I tried using this.physics.add.collider(this.player.sprite, groundLayer); which does work, but the slopes are turned into rectangles.
With matter, it seems like the collision is enabled by default, and the only instance of using a collision code is to trigger an event, which isn’t necessary.
I don’t want to convert my player sprite to matter since it’s a lot of work and quite complicated with my level of knowledge.
Here’s my code.
My level file:
import Player from './Player.js';
export default class Field01 extends Phaser.Scene {
constructor () {
super({
key: 'field01',
physics: {
arcade: {
debug: true,
gravity: { y: 0 }
},
matter: {
debug: true,
gravity: { y: 0 },
debugShowBody: true,
debugBodyColor: 0x0000ff
}
}
});
}
preload()
{
this.load.image('tiles', 'assets/tilemaps/tiles/overworld-ground.png');
this.load.tilemapTiledJSON('map', 'assets/tilemaps/maps/Field01.json');
this.load.image('ground', 'assets/platform.png');
this.load.spritesheet('dude', 'assets/sprites/characters/link.png', { frameWidth: 16, frameHeight: 24 });
}
create()
{
var platforms;
var player;
this.map = this.make.tilemap({ key: 'map' });
this.map.landscape = this.map.addTilesetImage('fieldfare', 'tiles');
const groundLayer = this.map.createLayer("ground", [this.map.landscape], 0, 0);
this.map.setCollisionBetween(2,9);
this.cameras.main.setSize(256,224);
this.cameras.main.setBounds(0, 0, this.map.widthInPixels, this.map.heightInPixels);
this.player = new Player(this, 352, 48);
this.add.existing(Player);
this.cameras.main.startFollow(this.player.sprite);
this.cameras.main.setDeadzone(4,4);
platforms = this.physics.add.staticGroup();
platforms.create(64, 64, 'ground');
groundLayer.setCollisionByProperty({ collides: true });
this.matter.world.convertTilemapLayer(groundLayer);
this.physics.add.collider(this.player.sprite, groundLayer);
this.physics.add.collider(this.player.sprite, platforms, function(player, platforms) { this.scene.switch('Level1'), player.y += 48}, null, this);
}
update() {
this.player.update();
}
}
My player 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 my game config file;
import Field01 from "./Field01.js";
var config = {
type: Phaser.AUTO,
width: 256,
height: 224,
pixelArt: true,
input: {
gamepad: true
},
physics: {
default: 'arcade',
arcade: {
gravity: { y: 0 },
debug: true
}
},
scene: [ Field01 ]
}
var game = new Phaser.Game(config);
And my index file:
<!DOCTYPE html>
<html>
<head>
<script src="phaser.js"></script>
<script src="matter.js"></script>
</head>
<body>
<script type="module" src="game.js"></script>
</body>
</html>
Anything I can do?
If I have to change to matter, then how would I properly convert it? This is just a last resort if nothing else is possible.
2
Answers
I managed to figure out how to convert my arcade player to matter.
Here's how I did it for anyone that has this issue and finds this in the future.
First off I changed the add sprite line of code in my player file. I replaced "Physics" with "Matter"
Next I changed the update section and removed the "body" part out of the
And all the others.
Now it should looks like this.
I also replaced the "speed" with numbers so I can easily control the speed the player goes when diagonal or straight. I also removed the
and
line since they're not necessary anymore.
Now it should work. But now there's one problem. The player sprite rotates when it moves along the walls. I fixed that problem by adding this line of code at the bottom of the Create() function in the player file.
Now the player's angle is fixed and no longer spins.
The player collides with the map as I intended now.
Here's the full code for the player file.
My answer is abit too late, but I was working on the demo. 🙂
Honestly if you are using the
matter
engine only for the sloped tiles you should remove thematter
engine, this is a overkill for that little bit of functionallity, and a solution where an object (the player) usesmatter
andarcade
physics will be very hacky.I would suggest living with the non-sloped tiles, But if you want to use arcade and matter here is a hacky solution. I attaching a matter object to a arcade object. With
matter
– collisions events andthis.player.body.reset(...)
to set the position of the aracde body.