Posted at
phina.jsDay 15

phina.jsとFirebaseで簡単にオンラインゲームを作ってみる

More than 1 year has passed since last update.

この記事は、phina.js Advent Calendar 2016 12月15日の記事です。

昨日→phina.jsで加速度センサーを使ったミニゲームを作る by simiraaaaさん

ネタ的にtamochu3141さんの記事phina.jsでの多人数参加型ゲームの作製と被り気味ですが、気にせずいきます。


Firebaseとは

こちらの記事で詳しく説明されておりますのでご参照ください。


手軽なオンライン対戦環境が欲しい…欲しくない?

大昔、こんなゲーム作って「やっぱりオンラインで対戦してみたいよね」と思って、さくらにサーバー借りてnode.jsでサーバ側スクリプト書いたりしてみましたが、簡単な事をするのにも結構大変で難儀しました。(現在はサーバーを止めている為、オンライン対戦は動作しません)

最近になって、FirebaseというBaaSがあるという事を知ったので、手軽にオンライン対戦環境を構築出来ないか試してみる事にしました。

Firebaseとの同期の為に、以下の様なアクセサリを作成しました。


phina.Firebase.js

phina.define("phina.Firebase.Receiver", {

superClass: "phina.accessory.Accessory",

_stop: false,
_val: null,

init: function(firebaseObject) {
this.superInit();
this.firebase = firebaseObject;

this._val = {};

//firebaseと情報を同期
this.firebase.on('value', function(snap) {
if (this._stop) return;
var v = snap.val();
this._val.$safe(v);
}.bind(this));
this.firebase.on('child_changed', function(snap) {
if (this._stop) return;
this._val[snap.key()] = snap.val();
}.bind(this));
},

start: function() {
this._stop = true;
return this;
},

stop: function() {
this._stop = false;
return this;
},

key: function() {
return this.firebase.key();
},

val: function() {
return this._val;
},
});

phina.define("phina.Firebase.Sender", {
superClass: "phina.accessory.Accessory",

_stop: false,
_data: null,

init: function(firebaseObject) {
this.superInit();
this.firebase = firebaseObject;
this._data = {};
},

start: function() {
this._stop = true;
return this;
},

stop: function() {
this._stop = false;
return this;
},

update: function() {
if (this._stop) return;
this.firebase.update(this._data);
},

setSendData: function(data) {
this._data = data || {};
return this;
},

remove: function() {
this.target.detach(this);
this.target = null;
this.firebase.remove();
return this;
},

key: function() {
return this.firebase.key();
},

val: function() {
return this._data;
},
});


Firebaseのデータベース内のオブジェクトに対するセンダーとレシーバーです。それぞれ、オブジェクトの内容の更新と取得を行います。

作ってみたら、アクセサリにする意味はありませんでしたが、アタッチしたオブジェクトが自動更新される様にするとか良いかもしれません。


使用方法

最初に、Firebase側の設定を行います。

詳しい設定方法割愛しますが、新規プロジェクトを作成して、URL等が取得出来ればオッケーです(手抜き)


FirebaseAPIをロード

<script src="https://cdn.firebase.com/js/client/2.0.4/firebase.js"></script>


firebaseのオブジェクト取得


Firebaseオブジェクトの取得

var firebase = new Firebase("firebeseのURL");

//下位オブジェクトの取得
var objects = firebase.child("objects");

phina.jsのクラスと違い、newが必要なので注意してください。

下位オブジェクトはFirebase側で用意する必要は無く、アプリケーション側からオブジェクトを取得or追加すると自動的に作成されます。


Firebaseへのオブジェクトの追加


Firebaseへオブジェクトの追加

this.player = this.objects.push({

type: "player",
name: "test",
age: 0,
x: SC_W*0.5,
y: SC_H*0.5,
});


クライアント側オブジェクト追加

objects.on("child_added", function(snap) {

//セッションキー
var key = snap.key();
//内容
var val = snap.val();

//クライアント側オブジェクト追加処理
//...
});


Firebaseでオブジェクトが追加されるとchild_addedイベントが発火します。

コールバック関数で追加されたオブジェクトの内容が引数として渡されますので、内容に応じてクライアント側で追加処理をします。


Firebaseオブジェクトの操作


Firebase側からオブジェクトを取得する場合

//アクセサリの定義

this.firebase = phina.Firebase.Receiver(firebase).attachTo(this);
//オブジェクトの取得
var data = this.firebase.val();


Firebaseへオブジェクトを送信する場合

//アクセサリの定義

this.firebase = phina.Firebase.Sender(firebase).attachTo(this);
//Firebaseへオブジェクトを送信
this.firebase.setSendData({
x: this.x,
y: this.y,
});

Firebaseとの情報の同期は自動で行われます。


自動更新の停止と再開

//自動更新停止

this.firebase.stop();

//自動更新開始
this.firebase.start();


自動更新の操作はセンダー、レシーバー共通です。


実際の動作サンプル

と言う事で、簡単ですがこんなのを作ってみました。

Firebaseでのオンライン対戦サンプル

カーソルキー左右で移動。上でジャンプ。

スペースキーで弾を発射します。

他に接続しているユーザーがいると、自分の画面にも表示されます。

当り判定はありません(対戦とはいったい)


良い点

同期させたいデータがJSONで一括取得出来るのは非常に楽で、あんまり難しい事を考える&覚える必要がありません。

特に、サーバーサイドの作り込みが不要なのは大きいです。


悪い点

サンプルを実行すれば一目瞭然なのですが、かなりラグがあるので激しい動きのあるアクションゲーム等には不向きと思われます。

常に全データ同期するので、規模が大きくなってくるとデータ転送量的にヤバそうではあります。


おしまい

甚だ簡単ではありますが、オンラインゲームを作るのはサーバー側の知識も必要で相当にハードルが高いけど、使用するサービスによってはかなり楽に出来るよってお話でした。

いやー、技術の進歩って素晴らしい。

サンプルのソースはこちら[GitHub]