プログラミング素人のはてなブログ

プログラミングも電気回路も専門外の技術屋の末端が勉強したことや作品をアウトプットするブログ。コードに間違いなど見つけられたら、気軽にコメントください。 C#、Python3、ラズパイなど。

FirebaseのTwitter認証を使って掛け算暗算ゲームを作った

掛け算(99x99)暗算ゲームを作りました。
ゲーム部分はJavaScriptで構成し、成績の記録と個人認証にはFirebaseを使いました。
https://s51517765.firebaseapp.com/9999/index.html

f:id:s51517765:20190918115459p:plain
システム構成図

JavaScriptの切り離し

これまでは、index.htmlのなかにJavaScriptを書いていましたが、main.jsとして切り離し、メンテナンス性を高めるようにしました。

<script type="text/javascript" src="config.js" charset="utf-8"></script>
<script type="text/javascript" src="main.js" charset="utf-8"></script>

config.jsはFirebaseの認証情報が書かれたものです。こちらは基本的には変更されることもないので分離しておくほうがよいと考えました。
ただし、このときconfig.jsmain.jsの読み込み順はこの通りでないとだめなので注意です。config.jsの中身をmain.jsで使っているからです。

過去の記録の読み込み

FirebaseのRealtime databaseからforEachで呼び出し、3x2の連想配列に難易度ごとに分けて最大値を探索します。
連想配列とは辞書形式のことです。
このように難易度別に保持しておくことで、ゲーム結果が更新したかどうかをこれと比較して判定します。

var rank_in_Score = { "9": { "score": - 1, "name": "none" }, "19": { score: - 1, name: "none" }, "99": { score: - 1, name: "none" } }; //連想配列

function loadScore()
{
    database99.on("value", function (snapshot)
    {
        snapshot.forEach(function (childSnapshot)
        {
            var childData = childSnapshot.val();
            if (parseInt(childData.score) > rank_in_Score[childData.difficulty]["score"])
            {
                rank_in_Score[childData.difficulty]["score"] = parseInt(childData.score);
                rank_in_Score[childData.difficulty]["name"] = childData.name;
            }
        });
        document.getElementById("9_score").innerHTML = rank_in_Score["9"]["score"]
        document.getElementById("9_name").innerHTML = rank_in_Score["9"]["name"]
        document.getElementById("19_score").innerHTML = rank_in_Score["19"]["score"]
        document.getElementById("19_name").innerHTML = rank_in_Score["19"]["name"]
        document.getElementById("99_score").innerHTML = rank_in_Score["99"]["score"]
        document.getElementById("99_name").innerHTML = rank_in_Score["99"]["name"]
    });

}

時間管理・タイマー処理

解くことが出来た問題数を競うゲームなので時間制限を使う必要があります。
また、問題が正しく解かれたことを判断するために入力があるたびにその入力が正解かどうかを判定する必要があります。

これにはsetIntervalという関数で定期的に入力欄を監視します。
これには、intervalごとにanswerCheckという関数を呼び出す設定で実現できます。

timer = setInterval(answerCheck, interval); //タイマースタート

timerと名前を付けておくことで、停止処理もできます。

function end()
{
    clearInterval(timer); //タイマーストップ
}

同時に時間切れも判定します。

function answerCheck()
{
    if (nowTime - startTime > 1000 * Time)
    {
        end();
    }
}

C#のtimerと同じような感覚で使うことが出来ました。

Twitter認証

新記録を出したときにTwitter認証をしてランキングする仕組みを作りたかったのでFirebaseを使った、というところがあります。

記録を更新したら、Twitter認証をします。
Twitter認証は↓をほぼそのまま使わせていただきました。
blog.katsubemakito.net

FirebaseのTwitter認証でとれる情報はScreen_nameだけのようです。
Twitter IDを取得できれば、ランキング表にその人のProfileへのLinkを貼ることが出来るとよいかと思ったのですが、Firebaseではそのような機能は提供されていないようです。FirebaseのTwitter認証で生成されるIDはあくまでFirebaseでのIDのようです。

ページ間でのデータの受け渡し

メインのゲームのページindex.htmllogin.htmldone.htmlの間でデータ(ここではゲームの難易度設定とスコア)を受け渡すには「URLのパラメーター」という方法が使えます。
これは

遷移先のurl + ? + parameter

のような形で値を渡す方法です。
遷移先のページで↓のようにして値を取得します。

var data = (window.location.search).slice().split('&');
var score = data[0].split('=')[1];
var selected_difficulty = data[1].split('=')[1];
document.getElementById("score").innerHTML = score;
document.getElementById("difficulty").innerHTML = selected_difficulty;

qiita.com

tableのCSS

ランキング表はtableで作成しましたが、そのデザインはCSSで作成しています。
サンプルコードほぼそのままです。
【コピペOK】CSSだけで実装できるおしゃれテーブルデザイン10つ | webliker

ブラウザのキャッシュ

変更を加えながらdeployしていると、サーバー上のdeployが反映されないことがありました。
Chromeブラウザのキャッシュが原因のようで、「Ctrl」+「F5」でキャッシュを無視して更新するか、キャッシュを削除すると解消します。

まとめ

Firebaseを使えばTwitter連携も簡単です。
s51517765.firebaseapp.com


参考