Among Us Scratch の解析1:プロジェクトの外観と背景
プロジェクト外観
☁️ 保存版Among Us Scratch remake v2.1 (WIP) ✦ TimMcCool games remix copy
ブロック数は 16552 、コスチュームは 1008 とかなり巨大なプロジェクトだ。規模に応じて中は複雑な仕組みになっていそうだ。
背景(ステージ)は真っ黒、スプライトは45個。スプライトにはプレイ中に出てくるキャラクタやマップ絵のコスチュームを持つものもたくさんあるが、どう動いているかは全く不明。
まず、アプリケーションを起動すれば必ず動く「背景」から中身を見ていくことにする。
背景のコスチューム
「背景」はプロジェクト(アプリケーション)の画面全体を覆う1枚絵だ。
背景は1つのプロジェクトに1つしかなく削除や移動はできない。背景のないプロジェクトは作れず、背景を2つ以上作ることもできないので、背景は「常に1つだけ存在する」。
スクラッチは、ゲーム中に登場する「スプライト」や背景に、何枚かの絵を割り当てて切替表示ができる。この絵のことを「コスチューム」と呼ぶ。
Among Us Scrach v2.1 (WIP) の背景のコスチュームは backdrop1 と backdrop2 の2枚。
backdrop1 はディフォルトで真っ黒。backdrop2 は透明。backdrop2 は何に使うのか不明だが、大きさが 2×2 ピクセルと、妙に怪しいサイズ。何か特殊用途かもしれないが、今は全くわからない。
コスチュームはこの2つしかないところから、Among Us Scratch では、背景は、絵としては、真っ黒もしくは何もない状態でしか利用しないようだ。
背景のコード全体
スクラッチは、背景やスプライトに「コード」と呼ぶプログラムを作ることができる。コードはブロックを重ねたもので、基本的には「上から下へ」実行される。また、1つのブロックの塊を「スクリプト」と呼ぶこともある。
上の写真は背景のコード全体を見渡したものだ。すごい量、というほどではなかったので少し安心。塊をひとつづつ確認していく。
背景のコード1:最初のモード設定コード
「旗が押されたとき」はアプリケーション起動時に動かすコードの先頭につけるイベント。だから、このコードはゲーム最初に動く。イベントを付けたコードはいくらでも作れるので、このコードはあくまで最初に動くものの「1つ」である。
modus はゲームの「モード」を表す変数。Among Us Scratch プログラムで定義しているものだ。ここでは初めにモードとして "intro" (最初のタイトル画面の状態)を設定している。
スクラッチには、変数の状態を画面の適当な場所に表示させておく機能があるので、modus 変数を表示させてプレイすれば、各画面に割り当てられたゲームのモード名を見ることができる。いくつか次に紹介する。
intro モード: 最初のタイトル画面
online モード: タイトルでONLINEを選んだ後の初期メニュー選択画面
before-cng モード: online モードで host を選んだ後の画面
find モード: online モードで public を選んだ後の画面
joining モード: online モードで join by code を選んだ後の画面
そのほかにもいろいろなモードがあると予想されるが、いつでもどこでも modus 変数を見ればどんな画面か確認できるので、ゲームモードに応じた動作をするコードを背景やスプライト作ることができる。この後に説明する、ゲームモードに応じて音量を変える人はそのようなコードだ。
modus変数の設定と同時に、モードと同名の "intro" イベントも送っている。intro モードになったときに動かしたいコードがあれば、このイベントを受け取ればよい。しかし、背景には、この "intro" イベントを受け取っている所がなく、今のところ何をしているのか全くわからない。
余談だが、そもそもスクラッチには、イベントや変数を受け取ったり使ったりしている場所を検索する機能がまったくない。プログラミング環境としては強烈な欠点であり、このnoteのようなプログラムの理解にも使いづらい。是非入れて欲しい機能の一つだと思う。
introモードに限らず、modus 変数を変えるときは同名のイベントを送信するのが、Among Us Scrach v2.1 (WIP)でのルールとなっているようだ。
これにより、「今なんのモードか」だけでなく「モードが変わった時」を検知して動くコードを作ることができる。簡単だが大切なプログラミングルールだ。スクラッチには、プロジェクトのコード全てに何かを通知する手段は、変数とイベントしかない。
最期にステージ(背景)を「全部消す」している。よくわからないけど、プログラムが動いたら、まず画面はきれいに消さないといけないような気がする。昔のパソコンBASICのプログラムだって10行目はCLSって書いてるものが多かったと思う。
背景のコード2:謎の __length-of-output 変数
これもゲーム開始時に最初に動くコード。いきなり何しているのかまったく不明なコード。だいたい「もし」の中が空だ。
永遠に __length-of-output を send to cloud という変数のもつ文字列の長さに設定している。しかもその中で長さが 256 を超えたなら何かするつもりで空っぽ。デバッグ用のコードを突っ込むところだろうか。256 を超えると困る制約でもあるのかどうか。
少なくとも __length-of-output で何かをするコードがないなら、このコードは「動いているけど何もしない」はずなので、__length-of-output 使用箇所が見つかるまでは忘却放置する。
背景のコード3:メニューBGM
"AMONG US -Menu Theme" は起動後のタイトル画面からなっている曲。無限ループ。音楽が終われば「ずっと」によって、また最初から音楽を流しはじめる。
無限ループだが、後で説明する「ゲームモードに応じて音量を変える人」で音量コントロールされるので必ずしも鳴り続けることはない。このコードはあくまで「BGMを鳴らし続ける」ことに集中していて、そのほかの仕事は他人任せだ。単一の責任しか果たさないコード。素晴らしい。
背景のコード4:set_volume を送り続ける謎の人
起動してずっと set_volume イベントを送り続けるコード。スクラッチプログラムは、通常「ずっと」コードを使うと、その中身は毎フレームごとに動作するので、この set_volume イベントは毎フレーム送られる。
試しで、「ずっと」コードを外して動かなくしても、ゲーム動作の違いがわからなかった。どういう目的で動いているか不明。
このループがアニメーションのフレームに合わせて動くというのは、実はすこし細かいスクラッチらしいカラクリがある。詳細は第6回で解説する。
背景のコード5:ゲーム全体の処理速度を計測するコード
コードだけでは何をしているかわかりづらいが、変数名から処理の意味が予測できる。
TICK: ゲームでアニメーション1コマ(フレーム)分の経過時間や処理回数、という意味で使うことの多い名前。
FPS: Frame Per Second。1秒あたりに処理できたアニメーションのコマ数。高速なPCで実行していれば、アニメーションコマ数が増えてなめらかになり、FPSも上がる。
turbo mode: スクラッチの高速実行モード。普通のプレイ速度で実行するとなかなか目的の動作確認ができないときに、処理速度を上げて高速に進行させるスクラッチの機能。
このコードは、次の3つの処理をしている。
1: FPS を計る。
「ずっと」ループの中の最初のこの部分で、1秒おきにそれまで処理したコマ数=__TICK を加算して1秒分の処理フレーム数を記録する変数=__FPS に設定している。
__FPSが決まったら、__TICK は0に戻す。__TICKはどこかきっと別のところでフレーム1回処理されるたびにカウントアップされているだろう。後述するが、この背景コード群の中にその断片がある。
2: turbo mode かどうかを調べる。
turbo mode はアプリケーションを作るには便利な機能だが、普通にプレイしてもらって使われるには都合が悪い。特に Among Us のようなオンラインゲームでやられてしまうと、turbo mode の人だけ高速に動けて不公平だ。
そこで、Among Us Scrach v2.1 (WIP) は turbo mode でゲームをプレイすると、次の画面になってゲームに入れなくなっている。
スクラッチで公開されているアプリケーションには独自に turbo mode 検出して、turbo mode になったら動作を停止する仕組みを入れているものもある。
Among Us Scrach v2.1 (WIP)では、ゲーム全体が 40 FPS を超えることはないという前提で、40FPSを超えたら turbo mode として turobo_mode_detected イベントを誰かに送って、受け取ったどこかのコードが何かをする。
このコードは、先ほどのFPS計測の「ずっと」ループ内にあり、プレイ中ずっとチェックされている。
3: FPS がプレイに影響があるほど低いかどうか調べる
古いPC等環境があまりよくないと、スクラッチ自体の処理に時間がかかり、ゲームのFPSも低くなる。その検出もしている。
FPSが13未満なら __FPS_too_low を増やし、逆に13以上なら問題がないということなのか __FPS_too_low を0にしている。
__FPS_too_low がある程度以上の大きくなるなら、何秒もFPSが13以下になっているのだから、何かアプリケーションで警告をだしたりするのかもしれないが、どこで何しているのかは、まだわからない。
背景のコード6:フレーム数TICKを数える
FPSを調べるのに必要な、1秒間に処理したフレーム数を記録する __TICK 変数は、同じ背景の別のコードでカウントされている。
「_tick 2 を受け取ったとき」ブロックは「旗を押したとき」に似ている。違いは、tick 2 はコードのどこかから「送られる」ものという点だ。Among Us Scratch プロジェクトのどこかに tick 2 イベントを送るコードがあるということになる。
__TICK 変数は、tick 2 イベントを受けたときに1つ上がる。__TICK 変数は実行したフレーム数を数える変数として使っているようだから、アプリケーションのどこか「1フレームの処理をした」と決定できる責任コードが tick 2 イベントを送っているはずなのだが、背景のコードにはない。
とにかく「1フレーム分の処理が完全に終わる度に、tick 2 を誰かが送っているはず」と心にとどめておく。
背景のコード7:ゲームモードに応じて音量を変える人
この縦の長さのわりに妙に横に長いコードは、モードによって音量を変える処理をしている。
1. 実際のプレイ画面になるまで待つ。
2. 音量である #volume 変数を0にする。
3. intro等の実際のプレイ中ではない画面になるまで待つ。
4. 音量を元に戻して、1 に戻って繰り返し。
#volume 変数はゲーム中のマスターボリューム(主音量)のようなものを表すらしい。このコードにより、上で紹介した画面(プレイ中ではない画面)では音量が上がり、プレイ中は音量が0になる。
ここで音量処理をしてくれているので、きっと、プレイ中の画面のコードや、intro 画面の処理をするコードで、音量のことを気にする必要がなくなっているのだろう。
実際、最初のBGMを鳴らし続けるコードの音は、この音量調整があるので、画面ごとの処理をまったくしていない。音を鳴らす処理は、音を鳴らすコードの責任、音量を調整する処理は、音量を調整するコードの責任だ。
しかし、プレイ中の音量が0なのは、それでいいのかどうか不明。#volume とは違う変数管理だったりするのだろうか。
変数の種類
ここまでに出てきた変数はすべて「グローバル変数」なので、ここで紹介している背景コードだけではなく、このプロジェクト内すべてのプロジェクトの中のコードのどこからでも参照できる。
スコープで分類するなら、スクラッチにはグローバル変数のほかに、「スプライト用変数」と「クラウド変数」と「リスト」がある。
グローバル変数:どこからでも参照できる。スクラッチでは「すべてのスプライト用」の変数と呼ばれる。
スプライト用変数:個々のスプライトの中だけで参照できる。スクラッチでは「このスプライトのみ」の変数と呼ばれる。
クラウド変数:サーバー保存され全ユーザーから共通に参照できる。
リスト:グローバル変数だが、複数の値をデータとしてとる変数。スクラッチ唯一のコレクション型なので貴重。
このほか、変数とは分類されていないが、プロシージャや関数に相当する「ブロック定義」に渡す「引数」もある。
ゲームモードやボリューム等はグローバル変数が適しているが、Among Us Scrach v2.1 (WIP) のプロジェクトは大きいのでスプライト用変数も多用している。
変数は、開発環境のツールの中の「変数」と、実行中の画面の二か所でみることができる。ツール中の「変数」は次のような表示。
クラウド変数には雲マークがつくが、ほかは区別がつかない。左のチェックは実行中に値を表示するかどうかのデバッグ機能で、そのときの実行画面は次のようになる。
こちらでは、スプライト用変数の名前には、先頭にスプライト名「あるスプライト」が追加表示されるので、グローバル変数と区別がつけやすい。
背景のコード8:Joinしたら音を止めるコード
これだけ。きっとゲームが join game になったら、いったん音をすべて止めてオンライン参加状態(join)のモードの音を鳴らしたりするのだろう。
join game イベントを誰が送っているのかは、恒例通り、まったく不明。今後の調査が待たれる。
背景のコード9:オンラインプレイ中から抜ける処理
背景には、多分オンラインプレイ中の状態から抜けるときの処理(と思われる)コードがある。
trans1 というイベントを送って、そのイベントを受けた先がすべて処理を終了するのを待つのに、trans2というイベントは送るだけで待ち受けない。謎は深い。
trans1 trans2 という謎イベントの後は、modus変数を online にして online メッセージを送ることで、初期メニュー選択画面へ戻っている(多分戻るはずだが、背景のコードだけではまったくわからない)。
この2つのメッセージは、画面切り替わり時の暗転の処理であることが次々回に判明する。
背景のまとめ:抽象の壁
背景のコードについては以上ですべて。なんとなく全体フロー感のようなものは見えたような気はするが、詳細についてはまったくわからない。
逆に言えば、modus 変数やイベント等によりうまく抽象の壁が構築されていて、背景コード抽象度は、やたらとゲームの細かい処理をするようなことなく、一定の水準に保たれているように思う。
trans1 とか若干名前から意味が推測できないものもあるけど、さすがよくできたアプリケーションはプログラムも一味違うと思わせる。