Loading user-created Tiled stages on Phaser JS - Skate Platformer Game Devlog #11
Written in November 11, 2020 - 🕒 3 min. readHey guys, in today’s devlog I’m going to make something really cool - dynamically upload external Tiled map files created by the user.
First, let’s all get on the same page on how Phaser works. Phaser runs in an HTML canvas element that is attached to whichever HTML element ID you put on Phaser’s parent
settings option, so if I want a browser-related action like uploading a file using the HTML file-input element, I have to manually create that element and trigger it when needed.
const fileInput = new HtmlFileInput({
scene: this,
spriteKey: 'file-input',
});
const callBackFunction = () => {
// trigget the HTML file input click
fileInput.fileInput.click();
}
But what the hell is this HtmlFileInput
? It is basically a class that in its constructor I dynamically create an HTML input element and attach it to the page’s DOM. The styling part is there to make sure the element is not visible to the user.
class HtmlFileInput {
constructor({
scene,
spriteKey,
}) {
// Phaser's parent HTML element
const mainElement = scene.sys.game.canvas.parentElement;
// create html input type
const fileInput = document.createElement('input');
fileInput.setAttribute('type', 'file');
fileInput.setAttribute('accept', '.json');
fileInput.setAttribute('id', spriteKey);
// TODO this stylings
fileInput.style.position = 'absolute';
fileInput.style.top = 0;
fileInput.style.display = 'block';
fileInput.style.marginTop = '-400px';
mainElement.appendChild(fileInput);
this.setFileInput(fileInput);
this.setScene(scene);
}
setFileInput = (fileInput) => {
this.fileInput = fileInput;
}
setScene = (scene) => {
this.scene = scene;
}
}
export default HtmlFileInput;
I know this feels like a hack, but this is the proper way of doing it on Phaser 3, just don forget to remove the element from the DOM when you’re done with it by calling fileInput.fileInput.remove()
.
Now I need a way to parse the .json
file uploaded by the user and make it available on Phaser’s “cached file manager”, and the best way to do that is by using Phaser’s preload
function. First, let’s take a look at how the actual callback function works.
const callBackFunction = (data) => {
fileInput.textfield.onchange = (e) => {
const reader = new FileReader();
reader.addEventListener('load', (event) => {
const result = JSON.parse(reader.result);
this.scene.start('CustomStageLoadingScene', {
stageKey: 'custom_stage',
stageData: result,
nextScene: 'GameScene',
});
});
reader.readAsText(e.target.files[0]);
};
fileInput.textfield.click();
}
As you can see, I am using FileReader
to load the file and passing it as a parameter to a new scene called CustomStageLoadingScene
that only exists as an aux scene to dynamically load the phase sent by the user.
class CustomStageLoadingScene extends Scene {
constructor() {
super('CustomStageLoadingScene');
}
init(data) {
// data sent as a second parameter when calling the scene
// will be available here
const { stageKey, stageData, nextScene } = data;
this.stageKey = stageKey;
this.stageData = stageData;
this.nextScene = nextScene;
}
preload() {
const { stageKey, stageData } = this;
// make the JSON data available to Phaser's internal cache
this.load.tilemapTiledJSON(stageKey, stageData);
}
create() {
const { stageKey, nextScene } = this;
// start the next scene
this.scene.start(nextScene, { stageKey, stageName: 'custom' });
}
}
Now that I have the data set with this.load.tilemapTiledJSON()
, I can create the new stage with scene.make.tilemap({ key: stageKey })
. Pretty neat, right?
And that’s all for today, please don’t forget to like and subscribe to my channel, and if these devlogs are of any use to you, let me know in the comments below. Thanks and until next time.
Tags:
- coding
- games
- javascript
- phaser
- phaser 3
- game devlog
- gamedev
- skate platformer
- super ollie vs pebble corp
- webpack
- tiled
Related posts
Post a comment
Comments
No comments yet.