Falling off platforms with Arcade Physics on Phaser JS - Skate Platformer Game Devlog #06
Written in October 1, 2020 - GamesHey guys! Today’s Game Devlog is a bit long, 15 minutes, but bare with me because there are a lot of interesting things going on in the game.
Stage Selection
To facilitate testing new stages, I decided to add a basic stage selection for the game, so I could test multiple stages in the same build instead of having to change a single file everytime. Now whenever I add a new stage file to the stages folder, that stage will automatically be included in the game bundle, thanks to some custom Webpack settings.
const CopyWebpackPlugin = require('copy-webpack-plugin');
const { promises: fs } = require('fs');
const stageFiles = await fs.readdir(STAGES_PATH);
// get only the JSON files
const stageJsons = stageFiles
.filter((stage) => stage.split('.')[1] === 'json');
const GAME_STAGES = JSON.stringify(
stageJsons.map((stage) => {
// eslint-disable-next-line import/no-dynamic-require
const stageData = require(`${STAGES_PATH}/${stage}`);
const stageName = getStageNameFromMap(stageData);
return {
stageName,
stageKey: stage.split('.')[0],
};
})
);
module.exports = {
plugins: [
new webpack.DefinePlugin({
GAME_STAGES,
}),
],
};
Then in the stage selection scene, you can access the stages via the GAME_STAGES
constant, so I loop through the stages data and create the stage selector game object.
let posX = 20;
let posY = 50;
GAME_STAGES.forEach((stageData, index) => {
const { stageKey, stageName } = stageData;
const stageSelector = new StageSelector({
scene: this,
x: posX,
y: posY,
stageKey,
stageName,
onClickCallback: (data) => {
this.scene.start('GameScene', data);
},
});
this.add.text(
posX + 8,
posY + 8,
`${index + 1}`.padStart(2, '0')
).setDepth(50);
this.add.existing(stageSelector);
stageSelectors.add(stageSelector);
posX += 52;
if ((index + 1) % 7 === 0) {
posY += 52;
posX = 20;
}
});
Parallax Effect
The game wouldn’t be complete without a nice parallax effect, and to achieve that I decided to add some custom properties to the layers on Tiled, and read them in my scene’s update function to make the layer current position X or Y move accordingly with the camera movement.
update(time, delta) {
const { dynamicLayers } = this.mapData;
Object.values(dynamicLayers).forEach((dynamicLayer) => {
dynamicLayer.layer.properties.forEach((property) => {
const { name, value } = property;
if (value !== 1) {
if (name === 'parallaxSpeedX') {
dynamicLayer.setX(
this.cameras.main.scrollX * value
);
} else if (name === 'parallaxSpeedY') {
dynamicLayer.setY(
this.cameras.main.scrollY * value
);
}
}
});
});
}
Note: After writing this post, I found out about the setScrollFactor function, so I can use that instead, which takes way less processing power than looping in the update function.
Falling Off Platforms
To make this I did a bit of researching, and the way it’s done is a bit hacky, but it works for now so I decided to just roll with it.
First I check if the hero is in the ground, if there is a element the hero from below and if the down button is pressed. If so, then we disable the player bottom collision for 150 milliseconds.
// Handle hero going down through element
if (
this.isHeroOnGround()
&& this.isDownJustDown()
&& this.touchingDownObject
) {
this.body.checkCollision.down = false;
this.scene.time.delayedCall(
150,
() => {
this.body.checkCollision.down = true;
}
);
}
This is pretty straight forward, but how can we access the this.touchingDownObject
attribute? Well that’s the biggest hacky part of this solution. First, we need to add a collider between the hero and the map layer with a callback that will check some stuff and set the this.touchingDownObject
attribute for the hero.
this.physics.add.collider(
dynamicLayers.ground,
this.hero,
(objectA, objectB) => {
const [hero, element] = this.getHeroAndObject(objectA, objectB);
if (
hero.isHeroOnGround()
&& element.properties.collidesUp
&& element.properties.canFallThrough
) {
hero.touchingDownObject = element; // TODO?
} else {
hero.touchingDownObject = null;
}
}
);
That’s it! I hope you guys enjoyed it and don’t forget to leave your comment if you liked this post.
Tags: