Firebaseでゲームにランキング機能を付ける

概要

個人的にFirebaseを勉強中。
ラフでも良いので成果物を作りたくて…

大昔に作った蛇のゲームにランキング機能をつけてみました。

結論

少し雑ですが下記のようになりました。
https://hashito.biz/snake/

スクリーンショット 2019-10-12 23.14.48.png

##仕組み

  • ホームページ自体をFirebase Hostingに移動
  • ユーザはログインをしなくてもランキング情報を参照できる(参照のみ)
  • ログインしてゲームを行うと得点情報名前情報Firestoreに保存
    (このときの書き込み権限はユーザ毎にしか付与していません。)
  • ランキング情報はFirestore並び替えリミットで作成

実装

ここではゲーム自体ではなくランキング機能部分を重点的に説明していきます。
前提としてFirebaseの初期設定やHostingなどの解説は飛ばしています。
ご了承ください…

1.データ定義

今回はシンプルに名前と得点だけです。
こちらはFirestoreのUIにて操作して作成しました。
スクリーンショット 2019-10-12 23.25.19.png

基本的に、Firestoreはno sql形式で保存されているらしく…
一番端のコレクションというのがtable定義に近く、その中にドキュメントというkeyを持つフィールドが複数持てる仕組みなっています。
今回、私はsnake_usersというコレクションを定義し、ドキュメントにはユーザ固有IDを利用するようにしています。

こうしているのは次のルールの定義で「自IDと同じドキュメント(key)には書き込みできる!」と定義させるためです。

2.ルール定義

Firestoreではデータアクセスについてのルールを定義する事ができます。
これを利用すると「全員が参照できる!」とか「この人しか編集できない!」などが詳しく設定できます。

今回の定義はこんな感じです。
少し読めば分かると思うのですが…前提として全員不許可らしいです。
次に誰を許可するかと言うのを定義していく感じになります。

rules_version = '2';  
service cloud.firestore {  
  match /databases/{database}/documents {  
   match /snake_users/{userID} {  
      allow read: if true;     
      allow write: if request.auth.uid == userID;  
   }  
  }  
}  

このルールでは注目するべきは真ん中の二行ですね。

      allow read: if true;     
      allow write: if request.auth.uid == userID;  

一行目:誰でもすべてのデータを見ても良い
二行目:ログインしているユーザのみデータを加工して良い

ということです。
前準備はここまでで、コーディングになります。

3.コーディング

3.1.ログイン

今回、私はgoogle連携による認証のみを利用しています。
ですので、ボタンクリックなどに下記のコードを実行させるだけで実現できます

var provider = new firebase.auth.GoogleAuthProvider();  
firebase.auth().signInWithPopup(provider).then(function(result) {  
}).catch(function(error) {  
});  

3.2.ログイン状態の確認

javascriptなどの実行時に認証済みのユーザかを確認する必要があると思います。
その場合は下記のようなコードで確認することが出来ます。

firebase.auth().onAuthStateChanged(function(user) {  
    if (user) {  
        console.log("login")  
    }else{  
        console.log("no login")  
    }  
});  

3.3.データの参照

今回、ランキング情報を参照するのにFirestoreに書き込まれたデータを参照しています。
下記のような方法でこれを実現しています。

var db = firebase.firestore();  
var cnf = db.collection("snake_users")  
cnf.orderBy('point').limit(10).get()  
    .then(function(q) {  
    self.ranking=[]  
    var cnt = q.docs.length  
    q.forEach(function(doc) {  
        var data=doc.data();  
        data.rank = cnt--  
        self.ranking.unshift(data)  
    });  
})  
.catch(function(error) {  
    console.log("Error getting documents: ", error);  
});  

orderBy('point')で並び替えを行い、limit(10)で件数を制限してランキング情報を作成しているのが分かると思います。

3.4.データの登録

最後は登録です。
先程定義したルールでログインユーザーのみしか書き込みが出来ないため、「①ログインを確認」し、「②ログインユーザーIDでデータ書き込み」という手順でデータを書き込んでいます。

firebase.auth().onAuthStateChanged(function(user) {  
if (user) {  
    var cnf = db.collection("snake_users").doc(user.uid).set({  
    name  : self.username,  
    point : self.snake.point,  
    }).then(function(docRef) {  
    console.log("Document written with ID: ", docRef);  
    self.get_ranking()  
    }).catch(function(error) {  
    console.error("Error adding document: ", error);  
    });  
}else{  
    console.log("no login")  
}  
});  

4.最後に少しだけ詰まった点

少しだけ詰まったのですが、Firebase Authを利用する場合に該当のドメインとサービス(今回はGoogle)を有効にする必要があります。
ご注意を…

スクリーンショット 2019-10-12 23.53.44.png スクリーンショット 2019-10-12 23.53.38.png

また、FirestoreなどはGCP(google cloud platform)と関連性が強いサービスなのでGCP側の設定が必要があるのでご注意を…

感想

Firebaseはかなり強力に感じました!
サーバーレスでここまで出来るんですから、色々と利用できそう…