LoginSignup
11
5

More than 3 years have passed since last update.

【Scratch3.0】Realtime Database拡張ブロックを作ったので参照実装したら既視感あるアレができちゃった件

Last updated at Posted at 2021-02-26

事始め

今年、弊社内ではゲーム制作コンテストが開催されており、私は運営チームとしてScratchのサポートを担当しています。Scratchの自主練をしていたところ、楽しそうな記事を見つけました。

そんなことができるのですね!

そしたら、Realtime Database のブロックとかつくって、ネットワークゲームも制作できるようになる......!!!

これはやるしかないでしょ、ということで。

やってみた事とその結果をまとめます。
なおNode.jsは今回初めて触りましたので、変な事していたらそこは温かい目で見守っていただければ幸いです。

環境構築

Windows上で行います。作業ディレクトリは次の場所にしました。

mkdir C:\Users\kami_teru\source\repos\scratch\
cd C:\Users\kami_teru\source\repos\scratch\

以下の記事を参考に、Node.jsをインストールし、scratch-gui をlocalhostで起動できるようにしました。

一つだけ注意点。私のWindows環境では npm run deploy を実行したとき、次のエラーが出ました。

powershell
PS C:\Users\kami_teru\source\repos\scratch\scratch-gui> npm run deploy

> scratch-gui@0.1.0 deploy C:\Users\kami_teru\source\repos\scratch\scratch-gui
> touch build/.nojekyll && gh-pages -t -d build -m "Build for $(git log --pretty=format:%H -n1) [skip ci]"

'touch' は、内部コマンドまたは外部コマンド、
操作可能なプログラムまたはバッチ ファイルとして認識されていません。

touchコマンドは、Git for Windowsをインストールしている方なら、次のようにすれば利用可能になります。

powershell
$ENV:Path+=";c:\Program Files\Git\usr\bin"

さてさてこれで、Scratchを試せるようになりました。

  • Scratch 3.0 GUI - 127.0.0.1:8601 Scratch 3.0 GUI - teru.k.business - Microsoft​ Edge 2021_02_26 9_39_51.png

次は、Realtime Database の準備を行います。

Realtime Database のセットアップ

1) Firebase プロジェクトの作成

Firebaseコンソールにアクセスし、プロジェクトを追加します。

設定項目
名前 (任意の名前)
Google アナリティクス 無効にする

アナリティクスは有効にすると、これから作る拡張ブロックの利用頻度などが取得できるようになるのでお勧めですが、本記事に関係のない情報なので無効にします。

2) Firebase プロジェクトに Webアプリ を追加

Scratch 3.0はNode.jsで動作するクライアントサイドのWebアプリなので、次のようにします。

設定項目
アプリのニックネーム (任意の名前)
Firebase Hosting 設定しない

LLK/scratch-gui は、Github Pages にデプロイする仕組みを備えており、本記事もそれを利用します。よって Firebase Hosting は設定しません。

Webアプリを登録すると、 Firebase SDK の追加 のページで「この作業は Firebase サービスを使用する前に行ってください。」という情報が表示されますが、あとで拡張ブロックからやるので、ここではスキップしました。

3) Firebase プロジェクトに Realtime Database を追加

Firebase コンソールの構築メニューから Realtime Database を選択。「データベースを作成」をクリックします。

設定項目
Realtime Databaseのロケーション 米国 (us-central1)
セキュリティルール テストモードで開始

拡張ブロックの動作確認までがとりあえずの目的なので、セキュリティルールはテストモードにしました。

4) Realtime Database への接続情報の確認

「プロジェクトの設定」ページを開くと、全般タブの「マイアプリ」セクションに作成した Webアプリ があります。それを選択すると、 Firebase SDK snippet 欄に次のような接続情報が表示されます。

<!-- The core Firebase JS SDK is always required and must be listed first -->
<script src="https://www.gstatic.com/firebasejs/8.2.9/firebase-app.js"></script>

<!-- TODO: Add SDKs for Firebase products that you want to use
     https://firebase.google.com/docs/web/setup#available-libraries -->
<script src="https://www.gstatic.com/firebasejs/8.2.9/firebase-analytics.js"></script>

<script>
  // Your web app's Firebase configuration
  // For Firebase JS SDK v7.20.0 and later, measurementId is optional
  var firebaseConfig = {
    apiKey: "AI***********************************WQ",
    authDomain: "************.firebaseapp.com",
    databaseURL: "https://************-default-rtdb.firebaseio.com"
    projectId: "************",
    storageBucket: "************.appspot.com",
    messagingSenderId: "************",
    appId: "1:************:web:**********************",
    measurementId: "G-**********",
    };
  // Initialize Firebase
  firebase.initializeApp(firebaseConfig);
  firebase.analytics();
</script>

***の部分が、作成したFirebaseプロジェクト固有の部分。

以上で準備完了!では Realtime Database 拡張ブロック づくりへ。

Realtime Database 拡張ブロックの作成

Scratch に Realtime Database 拡張機能 を追加

Scratch で Realtime Database 拡張ブロックを表示できるようにするための機能情報を記述するために、C:\Users\kami_teru\source\repos\scratch\scratch-gui のソースを編集します。

機能名は realtimedbとします。
src/lib/libraries/extensions/index.jsx に以下を追加。

src/lib/libraries/extensions/index.jsx
...(中略)...
import realtimedbIconURL from './realtimedb/realtimedb.png';
import realtimedbInsetIconURL from './realtimedb/realtimedb-small.png';

export default [
...(中略)...
    {
        name: 'Realtime Database',
        extensionId: 'realtimedb',
        iconURL: realtimedbIconURL,
        insetIconURL: realtimedbInsetIconURL,
        description: (
            <FormattedMessage
                defaultMessage="Connect to Realtime Database."
                description="Realtime Database"
                id="gui.extension.realtimedb.description"
            />
        ),
        featured: true,
        internetConnectionRequired: true
    }
]

src/lib/libraries/extensions/realtimedb/ 配下に、画像ファイルを配置。
Firebaseブランドガイドライン から適当なものをピックアップ&サイズを調整。

  • realtimedb.png
    realtimedb.png

  • realtimedb-small.png
    realtimedb-small.png

Realtime Database 拡張機能 の最低限の実装

いよいよ拡張ブロックの実装です。C:\Users\kami_teru\source\repos\scratch\scratch-vm のソースを編集。

まずは SDKの組み込み。Node.js から Realtime Database を利用する場合、Firebase SDK が便利です。
次のようにして、Firebase SDK をインストール。

powershell
cd C:\Users\kami_teru\source\repos\scratch\scratch-vm
npm install firebase --save

次に、Webサイトの Firebase認証 を済ませるための最低限の実装を行います。
こんなブロックを実装していきます。
スクリーンショット 2021-02-26 112416.png

src/extensions/scratch3_realtimedb/index.js
const ArgumentType = require('../../extension-support/argument-type');
const BlockType = require('../../extension-support/block-type');
const Cast = require('../../util/cast');
const log = require('../../util/log');
const firebase = require('firebase/app');
//require('firebase/analytics');
require('firebase/database');

const firebaseConfig = {};

class Scratch3Realtimedb {
    constructor (runtime) {
        this.runtime = runtime;
        this._firebaseApp = undefined;
        this._realtimedb = undefined;
    }
    get firebaseApp () {
        if (this._firebaseApp == undefined)
        {
            this._firebaseApp = firebase.default.initializeApp(firebaseConfig);
            //firebase.default.analytics();
        }
        return this._firebaseApp;
    }
    get realtimeDb () {
        if (this._realtimedb == undefined)
        {
            this._realtimedb = this.firebaseApp.database();
        }
        return this._realtimedb;
    }
    getInfo () {
        return {
            id: 'realtimedb',
            name: 'Realtime Database',
            blocks: [
                {
                    opcode: 'setApiKey',
                    blockType: BlockType.COMMAND,
                    text: '【設定1】apiKey は [TEXT] を使う',
                    arguments: {
                        TEXT: {
                            type: ArgumentType.STRING,
                            defaultValue: "Firebase SDK snippetから貼り付けてね"
                        }
                    }
                },
                {
                    opcode: 'setAuthDomain',
                    blockType: BlockType.COMMAND,
                    text: '【設定2】authDomain は [TEXT] を使う',
                    arguments: {
                        TEXT: {
                            type: ArgumentType.STRING,
                            defaultValue: "Firebase SDK snippetから貼り付けてね"
                        }
                    }
                },
                {
                    opcode: 'setDatabaseURL',
                    blockType: BlockType.COMMAND,
                    text: '【設定3】databaseURL は [TEXT] を使う',
                    arguments: {
                        TEXT: {
                            type: ArgumentType.STRING,
                            defaultValue: "Firebase SDK snippetから貼り付けてね"
                        }
                    }
                },
                {
                    opcode: 'setProjectId',
                    blockType: BlockType.COMMAND,
                    text: '【設定4】projectId は [TEXT] を使う',
                    arguments: {
                        TEXT: {
                            type: ArgumentType.STRING,
                            defaultValue: "Firebase SDK snippetから貼り付けてね"
                        }
                    }
                },
                {
                    opcode: 'setStorageBucket',
                    blockType: BlockType.COMMAND,
                    text: '【設定5】storageBucket は [TEXT] を使う',
                    arguments: {
                        TEXT: {
                            type: ArgumentType.STRING,
                            defaultValue: "Firebase SDK snippetから貼り付けてね"
                        }
                    }
                },
                {
                    opcode: 'setMessagingSenderId',
                    blockType: BlockType.COMMAND,
                    text: '【設定6】messagingSenderId は [TEXT] を使う',
                    arguments: {
                        TEXT: {
                            type: ArgumentType.STRING,
                            defaultValue: "Firebase SDK snippetから貼り付けてね"
                        }
                    }
                },
                {
                    opcode: 'setAppId',
                    blockType: BlockType.COMMAND,
                    text: '【設定7】appId は [TEXT] を使う',
                    arguments: {
                        TEXT: {
                            type: ArgumentType.STRING,
                            defaultValue: "Firebase SDK snippetから貼り付けてね"
                        }
                    }
                },
                {
                    opcode: 'setMeasurementId',
                    blockType: BlockType.COMMAND,
                    text: '【設定8】measurementId は [TEXT] を使う',
                    arguments: {
                        TEXT: {
                            type: ArgumentType.STRING,
                            defaultValue: "Firebase SDK snippetから貼り付けてね"
                        }
                    }
                },
                {
                    opcode: 'setText',
                    blockType: BlockType.COMMAND,
                    text: '[PATH] の [VALUENAME] に [TEXT] をセット',
                    arguments: {
                        PATH: {
                            type: ArgumentType.STRING,
                            defaultValue: "データパス"
                        },
                        VALUENAME: {
                            type: ArgumentType.STRING,
                            defaultValue: "データ項目名"
                        },
                        TEXT: {
                            type: ArgumentType.STRING,
                            defaultValue: "データ値"
                        }
                    }
                }
            ],
            menus: {
            }
        };
    }
    setApiKey(args)
    {
        firebaseConfig.apiKey = Cast.toString(args.TEXT);
    }
    setAuthDomain(args)
    {
        firebaseConfig.authDomain = Cast.toString(args.TEXT);
    }
    setDatabaseURL(args)
    {
        firebaseConfig.databaseURL = Cast.toString(args.TEXT);
    }
    setProjectId(args)
    {
        firebaseConfig.projectId = Cast.toString(args.TEXT);
    }
    setStorageBucket(args)
    {
        firebaseConfig.storageBucket = Cast.toString(args.TEXT);
    }
    setMessagingSenderId(args)
    {
        firebaseConfig.messagingSenderId = Cast.toString(args.TEXT);
    }
    setAppId(args)
    {
        firebaseConfig.appId = Cast.toString(args.TEXT);
    }
    setMeasurementId(args)
    {
        firebaseConfig.measurementId = Cast.toString(args.TEXT);
    }
    setText(args) {
        const path = Scratch3Realtimedb.parsePathInput(args.PATH);
        const valueName = Cast.toString(args.VALUENAME);
        const text = Cast.toString(args.TEXT);
        var data = {};
        data[valueName] = text;
        this.realtimeDb.ref(path).set(data);
    }
}
module.exports = Scratch3Realtimedb;

※アナリティクスを利用する場合はコメントアウトの箇所を有効にします。

最低限の実装ができたら、それを機能の一覧に登録するために記述を追加。

src/extension-support/extension-manager.js

const builtinExtensions = {
...(中略)...
    realtimedb: () => require('../extensions/scratch3_realtimedb')
};

では、ローカルで動作確認してみます。ビルドしてスタート。

powershell
cd C:\Users\kami_teru\source\repos\scratch\scratch-vm
yarn install; yarn link
cd C:\Users\kami_teru\source\repos\scratch\scratch-gui
yarn link scratch-vm; yarn install
yarn start
  • Realtime Database 拡張機能が表示されていますね!
    Scratch 3.0 GUI - teru.k.business - Microsoft​ Edge 2021_02_26 11_38_45.png

  • Firebase認証を通すためのプログラムを作って、一度実行。※アナリティクスを利用する場合は、設定8も実行します。
    スクリーンショット 2021-02-26 115154.png
    ※上記の認証情報は記事公開時点で削除しているので利用できません。

一度目はFirebase認証を通すだけになるので、Realtime Databaseへの書き込みは失敗するようです。
でもこれでWebサイトとしての認証が通りました。

  • 以降は次の設定だけのプログラムで、RealtimeDatabaseに接続できます。
    スクリーンショット 2021-02-26 115509.png

  • ちゃんと書き込めていますね!
    scratch-link - Firebase コンソール - teru.k.business - Microsoft​ Edge 2021_02_26 11_57_11.png

これと同じ手順を、Github Pagesでも行います。デプロイ。

powershell
yarn run build
yarn run deploy

同じように、Github Pagesに公開した Scratch からも Realtime Database に書き込めることが確認できました。

Realtime Database 拡張機能 の本実装

以下の技術情報を参考に、さらに機能を付け加えていきます。

以下、実装コードは、github のリンクから併読ください。

機能 ブロックイメージ ブロック情報 実装
データ階層の表現 スクリーンショット 2021-02-26 120453.png getInfo concatPath
文字データの送信 スクリーンショット 2021-02-26 122506.png getInfo setText
データ変更の監視 スクリーンショット 2021-02-26 122706.png getInfo listen
データ追加の監視 スクリーンショット 2021-02-26 122734.png getInfo listenChildAdd
データ受信の判定 スクリーンショット 2021-02-26 122758.png getInfo whenReceived
文字データの取得 スクリーンショット 2021-02-26 122831.png getInfo receiveText
追加された子階層名の取得 スクリーンショット 2021-02-26 122859.png getInfo receiveChildKey

ではいよいよ、これを使い方を示すものとなる参照実装を行います。

Realtime Database 拡張ブロック の参照実装

あいさつをほかのユーザーと共有してみた

まずは指定したパスの「データ変更の監視」と「データ受信の判定」と「文字データの取得」を中心に確認。
こんなプログラムにしてみました。
スクリーンショット 2021-02-26 161941.png

動かしてみましょう。
動作を確認するために、簡単なページを作りました。
※Github-Pagesのscratch-guiをiframeで呼び出してちょっと小細工したものです。
test01-1-min.gif

(2)で表示されたあいさつが、(1)のほうにも表示されましたね😄

データはこんな感じになりました。
スクリーンショット 2021-02-26 163310.png

どんどんいきましょう。

ユーザーが部屋に入ったらキャラクターを表示するようにしてみた

つぎは指定したパスへの「データ追加の監視」と「追加された子階層名の取得」を中心に確認。
プログラムはこんな感じ。

ねこ おともだち
スクリーンショット 2021-02-26 164314.png スクリーンショット 2021-02-26 164328.png

動かしてみましょう。

test01-2-min.gif

おぉぉ!お友達が部屋を訪れましたね!!😆
じろうさんの部屋にも、たろうさんがちゃんといます。

データはこんな感じになりました。
スクリーンショット 2021-02-26 174005.png

どんどん動かしてみた/つぶやけるようにしてみた

今度は Realtime Database拡張ブロックは使っていませんが・・・つぶやく機能を追加。

ねこ(追加分) おともだち
スクリーンショット 2021-02-26 165033.png 変更なし

まずはどんどん増やして・・・以下、9人目と10人目から。
test01-3-min.gif

おぉぉぉ、なかなかそうだいな画になってきましたね🤣
さらに20人追加してみましょう。性能テストですね。

スクリーンショット 2021-02-26 171350.png

ともだちがいっぱいでも大丈夫!🤣🤣🤣

これで好きな部屋に入って、会話を楽しみむことが出来ますね!!

でも・・・

あれっ?

こんなアプリ、どこかで見たような・・・

🦀🦀🦀 - 完 - 🦀🦀🦀

おわりに

例のパロディ作品のパクリでした(汗

なお今回作ったものは、以下の場所で公開しています。

11
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
5