DEV Community

Cover image for Phaser 3 - Saving and Loading dynamic maps (tilemaps)
matannahmani
matannahmani

Posted on

Phaser 3 - Saving and Loading dynamic maps (tilemaps)

About Me: I've been programming for just over 3 years and I'm currently looking for a job in web development/game design.

About the topic: I have seen many phaser 3 developers attempting to create dynamic maps, which could be saved and exported but they couldn't find the solution, so I decided to attempt and solve this problem.

About the Tools used: SQL (Postgres), ruby on rails for back-end API, Phaser3 and Reg-ex for basic security.

About the Level: This tutorial is meant for a complete beginner so everybody could understand! but remember in this tutorial I don't show a way to secure user route or use and authorization methods.

Example of usage : LastResort.pw

End Result map saved to the current user

Our first step is creating a rails app and setting up a Relational database:

I am using ruby on rails for this tutorial but this method could work on any other web framework.

Rails part starts here, setting new rails app with webpacker and Postgres DB

to create a new rails app with webpacker and Postgres DB

rails new $yourappname --webpack --database=postgresql

Database photo

In this database each user has base_commands column which will be an array of commands, we will touch this later.

The structure table contains two columns, placed and amount both being integer, which will represent the number of structures owned and the number of structures placed on the tilemap.

User_structures is a join table containing user structures.

We will start by generating all of our models :
structure, user and user_structures

rails g model structure amount:integer placed:integer
rails g model user
rails g model user_structure structure:references user:references

inside User migration file
t.string :base_commands, array:true, default: []

Then run the following commands
rails db:create
rails db:migrate

Now after we finished setting up our database will start working on models

In the User and Structure model, we add has_many :user_structure
In UserStructure model we add the following lines:
belongs_to :structure
belongs_to :user

Our next step now is to create Get and Patch routes so we could access our base_commands column.

rails g controller game

then in routes.rb (inside config folder) we add the following routes
get 'base/:id', to: "game#showbase"
patch 'base/:id', to: "game#updatebase"
in our game controller we add basic checking , and responding with JSON containing user base_commands.
see code in github

after creating all of our API endpoints we can finally start working inside our Phaser javascript file!

we will start by using the basic Phaser3 template:
const config = {
type: Phaser.WEBGL,
width: 375,
height: 812,
scale: {
mode: Phaser.Scale.RESIZE,
},
// parent : 'phaser-app',
scene: {
preload: preload,
create: create,
update: update,
}
}

after finishing our basic template we need to load our tileset to the phaser3 canvas.
we will create preload function:
function preload() {
this.load.image('tiles', 'url/tileimg.png');
this.load.tilemapTiledJSON('tilemap', 'url/tilemapjson.json');

tiles is the key for the image and tilemap is the key for the json

now will move to the create and update function:
function create() {
const map = this.make.tilemap({ key: 'tilemap' });
const tiles = map.addTilesetImage('16x16s', 'tiles');
const layer = map.createStaticLayer(1, tiles);
layer2 = map.createDynamicLayer(2, tiles);

function update() {}
Nice ! now will should have our map running on the canvas
Base Photo

Our next step is to create our Fetch calls, We will create two functions, first the loadBase that will give us the current user draw commands,
Second, the updateBase which will add our draw command to the user database.
you could also find improved version of functions in github

function loadBase() {
fetch('../base/1') // will get first user base
.then((response) => {
return response.json();
})
.then((commands) => {
commands.msg.forEach((command) =>{ // iterate over commands
eval(command); }) // execute each draw command
});
}

function updateBase(data) {
// Default options are marked with *
fetch('../base', {
method: 'PATCH', // *GET, POST, PUT, DELETE, etc.
mode: 'cors', // no-cors, *cors, same-origin
cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
credentials: 'same-origin', // include, *same-origin, omit
headers: {
'Content-Type': 'application/json'
// 'Content-Type': 'application/x-www-form-urlencoded',
},
redirect: 'follow', // manual, *follow, error
referrerPolicy: 'no-referrer', // no-referrer, *client
body: JSON.stringify(data) // body data type must match "Content-Type" header
}).then((response) => {
return response.json().then((data) => {
if(data['response'] == '500')
location.reload(); // reload page if failed placing
}) // parses JSON response into native JavaScript objects
});
}

You could see full example game
Or here at Lastresort.pw

Top comments (0)