Hello Phaser Community,
I’m working on a simple platformer game using Matter Physics. My game includes a tilemap, and a physics enabled sprite called the “player”. I’ve included the function to move the sprite, using A and D keys to move left or right, then using the space bar to jump. This is my current code:
scene1.js
// Import Gameobjects
import Player from "../objects/player.js";
import Enemy from "../objects/enemy.js";
export default class Game extends Phaser.Scene {
constructor() {
super("game");
}
create() {
// Debug
this.debugGraphics = this.add.graphics();
this.showCollidingTiles = true;
this.showFaces = true;
this.showTiles = true;
// Add Tilemap
this.map = this.make.tilemap({ key: "test-world" });
this.tileset = this.map.addTilesetImage("world-transparent", "tileset");
this.layers = {
ground: this.map.createDynamicLayer("ground", this.tileset, 0, 0),
obstacles: this.map.createDynamicLayer(
"obstacles",
this.tileset,
0,
0
),
functions: this.map.getObjectLayer("functions"),
};
// Add Sprites
// Sprite Shapes
this.shapes = {
player: this.cache.json.get('player_shapes')
}
// Player
this.player = new Player(this, 50, 0, "player");
// Tile Objects
// Create group for enemies
this.enemies = this.add.group();
this.layers.functions.objects.forEach((obj) => {
this.enemies.add(
new Enemy(this, obj.x, obj.y, obj.properties[1].value)
);
});
// Physics
// Tilemap Physics
this.layers.ground.setCollisionByProperty({ collides: true });
this.layers.obstacles.setCollisionByProperty({ collides: true });
this.layers.ground.setCollisionBetween(1, 999);
this.layers.obstacles.setCollisionBetween(1, 999);
this.matter.world.convertTilemapLayer(this.layers.ground, {
label: "ground",
});
this.matter.world.convertTilemapLayer(this.layers.obstacles, {
label: "obstacles",
});
// Collision Logic
this.matter.world.on("collisionactive", (e, a, b) => {
// Check if player is touching the ground
if (
e.pairs.some(
(pair) =>
pair.bodyA.label == "player" &&
pair.bodyB.label == "ground"
)
) {
this.playerOnGround = true;
}
// Check if player touches an obstacle
if (
e.pairs.some(
(pair) =>
pair.bodyA.label == "player" &&
pair.bodyB.label == "obstacles"
)
) {
this.scene.pause();
setTimeout(() => {
this.scene.start("game-over");
}, 1000);
}
});
// Misc
// Keyboard Input Object
this.keys = this.input.keyboard.addKeys({
jump: "SPACE",
left: "A",
right: "D",
});
// Camera
this.cameras.main.setBounds(0, 0, this.width, this.height, true);
this.cameras.main.startFollow(this.player);
this.cameras.main.zoom = 4;
this.cameras.main.setLerp(1, 0);
// Add world bounds
this.matter.world.setBounds(0, 0, this.scale.width, this.scale.height);
// Misc Variables
// Debug
}
update() {
// Misc variables that need to be updated every tick
this.player.setRotation(0);
this.enemies.children.entries.forEach((e) => {
e.setRotation(0);
});
// Movement
if (this.keys.right.isDown) {
this.player.flipX = false;
this.player.anims.play("walk", true);
// this.player.x += 5;
this.player.setVelocityX(2);
} else if (this.keys.left.isDown) {
this.player.flipX = true;
this.player.anims.play("walk", true);
// this.player.x -= 5;
this.player.setVelocityX(-2);
} else {
this.player.anims.stop();
this.player.anims.play("idle");
// this.player.setVelocity(0, 0);
}
// The jump mechanism is seperated from the if chain, and we used .on('down') because unlike the other movements, we only need to trigger the animation once.
this.keys.jump.on("down", () => {
if (this.playerOnGround) {
this.player.anims.play("jump", true);
this.player.setVelocity(0, -7);
this.playerOnGround = false;
}
});
}
}
Player.js
export default class Player extends Phaser.Physics.Matter.Sprite {
constructor(scene, x, y, key, options, frame) {
super(scene.matter.world, x, y, key, frame, options);
scene.add.existing(this);
this.body.label = 'player';
scene.anims.create({
key: 'walk',
frames: this.anims.generateFrameNumbers('player', {start: 8, end: 10}),
frameRate: 10,
repeat: -1
})
scene.anims.create({
key: 'jump',
frames: this.anims.generateFrameNumbers('player', {start: 0, end: 5}),
frameRate: 10,
repeat: 0
})
scene.anims.create({
key: 'idle',
frames: this.anims.generateFrameNumbers('player', {start: 0, end: 0}),
frameRate: 10,
repeat: -1
})
}
}
And this is a demo without me adding custom hitbox shape to the sprite:
https://drive.google.com/file/d/1ht4vFjaJr-fhDbBvvZULyYFsiODg21Mh/view?usp=sharing
Now, my problem arises when I use custom hitbox shapes in matter. I use this web app called Physics Editor and set my desired polygon. I successfully added the json file it generates to my code, then successfully imported the shape to my scene using:
// Add Sprites
// Sprite Shapes
this.shapes = {
player: this.cache.json.get('player_shapes')
}
// Player
this.player = new Player(this, 50, 0, "player", {shape: this.shapes.player});
I saw the hitbox shape is now different in-game, but unfortunately, the sprite seems to get stuck on the tilemap, as I cannot perform jumps anymore, even though I’m clicking the space bar. I tried to look at my jump function if there is something wrong with it, but I haven’t changed it before. This is a recording of the problem after I imported the custom hitbox shape…
https://drive.google.com/file/d/1fK6gCPIXnAdk4RXuUenmmpbt3W5gilZo/view?usp=sharing
As you can see, I’ve been hitting my space bar multiple times, but the sprite won’t jump.
I’ve been looking around google for almost an hour now and matter physics really gets me confused (I still need it tho). I’d really appreciate some help right now. Thank you everyone