In Mobsor version one I had created the beginning of a user management system but it was far from finished. Integrating Phaser and Firebase would have been easier both on me and the end-user.

In this version, I will be using Firebase because it offers all of the functionality I want and it’s free.

I have worked with Firebase on various past projects but I have never integrated it with Phaser.

Phaser 3 dom added login / register form

To begin with, I will just be using email-based authentication but a large list of capabilities are available.

I have so far only used and tested email-based authentication.

  • Phone (I believe this has a limit per time period)
  • Google (Similar to email but linked to user Google account?)
  • Play Games (I’ve only seen used on Android apps)
  • Game Center (Apple-based?)
  • Facebook
  • Twitter
  • GitHub
  • Yahoo
  • Microsoft
  • Anonymous (Could allow a user to begin play without creating an account and then register or abandon)

In this fork (github.com/matlintz/phaser3-typescript-webpack/tree/Firebase) I first updated all dependencies as every now and then things seemed to hang up during the build/browser-sync process. That is still happening now and then so I will take a deeper look at that when I have time. The production build should process the assets directory for a final package or folder to deploy to a live server with little or no finding of all things needed.

Next, I installed Firebase – npm install firebase –save

In the initial repo ( https://mobsor.com/blog/2019/07/getting-started-on-mobsor-version-ii/ ) I copied an existing phaser 3 boilerplate with no scenes or assets so I could use it as a base for anything.

Now I have added a menu scene that for now just allows a user to register or login and to set their Firebase display name.

Main.ts is now

import 'phaser';
import firebase = require("firebase/app");
import 'firebase/auth';
import firebaseConfig from './firebaseConfig';
import Menu from './scenes/Menu';
// Initialize Firebase
firebase.initializeApp(firebaseConfig);

const config: Phaser.Types.Core.GameConfig = {
  type: Phaser.AUTO,
  parent: 'content',
  dom: { 
    createContainer: true
  },
  width: window.innerWidth,
  height: window.innerHeight,

  resolution: 1,
  scale: {
    mode: Phaser.Scale.RESIZE,
    autoCenter: Phaser.Scale.CENTER_BOTH
  },

  backgroundColor: "#000000",
  scene: [Menu]
};

let game: Phaser.Game = new Phaser.Game(config);

I have not included firebaseConfig to the repo as it contains my Firebase info. It’s not really a security issue as any JavaScript-based Firebase project will expose this info.

Add your Firebase info to your project src/firebaseConfig.ts


let firebaseConfig:any = {
    apiKey: "api key here",
    authDomain: "your auth domain here.firebaseapp.com",
    databaseURL: "not using database but Firebase databaseURL will be here",
    projectId: "Your Project ID",
    storageBucket: "",
    messagingSenderId: "Your Messenger ID",
    appId: "Your appID"
  };
  export default firebaseConfig;

Menu Scene – Menu.ts

import Firebase = require("firebase/app");
import 'firebase/auth';
class Menu extends Phaser.Scene {
private user: Firebase.User;
private displayName: string;
private registerElement: any;
private userInfoElement: any;
private headerText: Phaser.GameObjects.Text;
constructor() {
super({
key: 'Menu'
});
}
hideRegisterElement() {
this.registerElement.removeListener('click');
this.scene.scene.tweens.add({ targets: this.registerElement.rotate3d, x: 1, w: 90, duration: 2000, ease: 'Power3' });
let self = this;
this.scene.scene.tweens.add({
targets: this.registerElement, scaleX: 2, scaleY: 2, y: 700, duration: 2000, ease: 'Power3',
onComplete: function () {
self.registerElement.setVisible(false);
}
});
}
showUserInfo() {
if (this.user !== null) {
let self = this;
this.userInfoElement.setVisible(true);
let inputDisplayName = this.userInfoElement.getChildByName("displayName");
inputDisplayName.value = this.user.displayName;
this.userInfoElement.addListener('click');
this.userInfoElement.on('click', function (event) {
if (event.target.id === 'closeSettings') {
self.userInfoElement.removeListener('click');
self.userInfoElement.setVisible(false);
}
if (event.target.id === 'saveSettings') {
//if name not changed then skip update to firebase
if (self.displayName != inputDisplayName.value) {
Firebase.auth().currentUser.updateProfile({ displayName: inputDisplayName.value }).then(
function (r) {
self.displayName = inputDisplayName.value;
//this doesn't work well on smaller screens
self.headerText.setText('Welcome ' + self.displayName);
let posX = self.cameras.main.centerX - (24 * (self.displayName.length / 2 + 8));
self.headerText.setPosition(posX, 25);
}
);
}
self.userInfoElement.removeListener('click');
self.userInfoElement.setVisible(false);
}
});
}
}
preload() {
this.load.svg('usericon', '/assets/icons/zondicons/user.svg');
this.headerText = this.add.text(this.cameras.main.centerX - 35, 50, 'Welcome', { fontFamily: 'Verdana, "Times New Roman", Tahoma, serif', fontSize: 48, fill: '#1212FF' });
let self = this;
Firebase.auth().onAuthStateChanged(function (user) {
self.user = user;
if (user !== null) {
self.hideRegisterElement();
self.displayName = self.user.displayName !== null ? self.user.displayName : self.user.email;
//duplicate code - move in future
self.headerText.setText('Welcome ' + self.displayName);
let posX: number = self.cameras.main.centerX - (24 * (self.displayName.length / 2 + 8));
if (posX < 1) { posX = 1; }
self.headerText.setPosition(posX, 25);
}
});
this.load.html('register', '/assets/html/register.html');
this.load.html('userinfo', '/assets/html/userinfo.html');
}
create() {
let self = this;
let userInfoButton = this.add.image(25, 25, 'usericon').setScale(.2).setInteractive();
userInfoButton.setTintFill(0xFFFFFF);
userInfoButton.on('pointerdown', this.showUserInfo, this);
this.userInfoElement = this.add.dom(this.cameras.main.centerX, this.cameras.main.centerY).createFromCache('userinfo');
this.userInfoElement.setVisible(false);
if (this.user == null) {
this.registerElement = this.add.dom(this.cameras.main.centerX, this.cameras.main.centerY).createFromCache('register');
this.registerElement.setPerspective(800); /* not quite sure what this does but found more info at https://photonstorm.github.io/phaser3-docs/Phaser.GameObjects.DOMElement.html */
this.registerElement.addListener('click');
this.registerElement.on('click', function (event) {
let inputUsername = this.getChildByName('username');
let inputPassword = this.getChildByName('password');
if (inputUsername.value.length > 0 && inputPassword.value.length > 0) {
//todo
//handle various error results from Firebase
if (event.target.id === 'Rlogin') {
Firebase.auth().signInWithEmailAndPassword(inputUsername.value, inputPassword.value).then(
function (r) {
self.hideRegisterElement();
}).catch(function(error){
alert(error.message);
});
}
if (event.target.id === 'Rregister') {
try {
Firebase.auth().createUserWithEmailAndPassword(inputUsername.value, inputPassword.value).catch(function (error) {
console.log(error); 
alert(error.message);
});
}
catch (error) {
console.log(error);
alert(error.message);
}
}
}
});
}
}
}
export default Menu;
/*
Reference Links:
https://www.phaser.io/examples/v3/view/game-objects/dom-element/form-input
*/

This was a quick run at integrating Phaser 3 and Firebase and not what I’d consider 100%. I still need logout functionality and for the menu state to change. Right now if you use dev tools and delete the firebase local DB the menu should update seeing that the same as a logout.

More work needs to be done on presentation and text size and positioning.

Could add the ability for the user to upload an avatar to tie to the Firebase account associated with the app.

Allow for and encourage email validation through the user settings dialog.

Current test version for this branch mobsor.com/phaser-firebase/

Leave a comment

Your email address will not be published. Required fields are marked *