見出し画像

Among Us Scratch の解析4:モード切替で使う効果

前回、ONLINEボタンを押して画面モードが切り替わるときの処理について少し調査を進めた。今回は、このモード切替時の動作について詳しく調べていきたい。

Among Us Scratch では、モードが切り替わるときは、切り替わり前の画面がふわっと消えて真っ暗になり(フェードアウト)、その後新しい画面画面がふわっと真っ暗な中から現れる(フェードイン)。

画像2

この効果がないと、画面を新しくする処理中の状態が見えてしまったり、突然違う画面に切り替わったりしてカッコ悪い。また、フェードアウトの開始=画面モードの切り替わりなので、モードの変化を画面自身がプレーヤーに知らせる役割もある。

簡単そうに見えるが、どの画面でも利用できるようにしなければならないし、Transitions スプライトはエラー表示などの処理もしていて、意外に込み入った実装になっている。

trans 系のイベントと Transitions スプライト

前回少し説明したとおり、画面を切り替えるときは trans1 や trans2 といったイベントを使用するのが Among Us Scratch のプログラミングルールとなっているようである。簡単には次のようなコーディング規約?だ。

画像3

trans1 で真っ暗になるまで待ち、その後、trans2 で画面をフェードインを開始する。そのとき同時に画面モードも切り替える。

この trans 系のイベントを処理しているのは、Transitions スプライトだ。スプライト表の一番下にある。

画像4

Transitions スプライトは Among Us Scratch の画面切り替えやフェードアウト・インの処理を引き受けているだけでなく、通信エラー等の時の特殊な画面処理も担っている。今回はこの Transitions スプライトの中身を見ていく。

Transitions スプライト:コスチューム

Transitions スプライトは機能が単純そうに見えて、コスチュームの数は 19 と比較的多い。だが、Transition スプライトのコスチュームを見れば Transitions の仕事内容がかなり理解できるので、いくつか例を挙げる。

normal コスチューム

真っ黒の全画面を覆う大きさ(480 x 360 ピクセル)のスプライト。一番最初から設定されているコスチューム。

このコスチュームを表示すれば、このコスチューム「より奥」にあるスプライトと背景は全く見えなくなる。

画像5

create コスチューム

normal と同じく真っ黒で画面大の大きさだが、

Creating new game ... 

(新しいゲームを作っています)

と書かれている。

画像6

このコスチュームは、ホストでゲームを開始するとき、参加者を待つ「待機部屋」の前に出てくる。次の動画画面右下の Confirm を押した後だ。

画像7

no_longer_exist コスチューム

やはり、真っ黒画面大だが、

The game you tried to join doesn't exist (anymore)!

(参加しようとしていたゲームはもう存在しません)

と書かれたコスチューム。

画像8

適当にルームを選んでプレイしようとしたら、ネットワーク切断などでホストに接続できなくなったとき等に表示される。次の動画は、ルームを選択して Joining game ... と出ているときに、ネットワークを強制的に切断してアクセス不能にしたところだ。

画像9

Transitions スプライトのコスチュームから、Transitions は画面のモード切替だけでなく、ユーザーを待たせるときの通知や、エラー等の表示の役割も持っていることがわかる。

また、動画でもわかるように、これらのメッセージを表示するときにも、本来のゲーム画面は見えないまま、メッセージにフェードアウト・フェードインが動作している。

1つのスプライト・1つの絵だけで、背景の黒塗りとメッセージの2重の効果を実装しているところは、Transitions スプライトのユニークなところだ。

Transitions スプライト:コード全体

Transitions スプライトのコードは少し多い。次の写真は、コードの全体の画面写真だ。

画像1

大きく分けると、Transitions スプライトには4種類のスクリプトがある。

1. 初期化。「旗が押されたとき」イベントの処理。

2.  エラーがあった時に表示する処理。

3. モード切替時のフェードアウト・フェードインの処理。

4. 特別な画面用のエラー表示。

他に、いつものごとく「存在に疑問のあるスクリプト」や「目的すら不明」なものもあるが、この4つを順に確認したあと、余裕があればそれらについても触れることにする。

Transition スプライト:1. 初期化

Transition スプライトの、アプリケーション開始時「旗が押されたとき」イベントのスクリプトは3つある。

初期化 1:コスチュームを normal /非表示設定して、表示を一番手前にする

画像10

最初のコスチュームをこのページの最初で紹介した normal (真っ黒だけ)に設定し、「隠す」で見えないようにしている。

次に「ずっと」ループで「最前面へ移動する」をしている。「最前面へ移動する」は、スプライトの表示順序を設定するものだ。

次の動画は、バナナの絵のスプライトの順序を変える例だ。最初「最背面」にしているので、どのスプライトよりも下に表示されているが、スペースキーを押したら「最前面」になり、どのスプライトよりも上に表示される。

画像13

(見づらいが、コードの表示のハイライトでプログラムが動いたタイミングがわかる)

この動画のように、最前面にするのは1度だけで十分そうには見える。それでも、「ずっと」で続けているのは、うっかり最前面になろうとするスプライトがあっても大丈夫にするためだろう。

Transitions の「ずっと」ループは、「スクリプトを止める」等で停止されない限り動作し続けるので、常に他のスプライトや背景の上にあり、いつでも「真っ黒の絵で他のものを隠す」準備ができている。

初期化 2:起動後最初にフェードインする。

2つ目の開始したときの処理は、起動直後にゲーム画面をフェードインする処理を行う次のスクリプトだ。

画像11

Among Us Scratch は最初に起動した直後もフェードインで intro 画面があらわれるようになっている。

画像14

「10回繰り返す」の部分がフェードインの部分で、幽霊の効果を使っている。

画像15

■ 幽霊の効果が0 = 真っ黒コスチュームが見える(幽霊ではない)

■ 幽霊の効果が100 = 真っ黒コスチュームは見えない(完全に幽霊)

最初「真っ黒」の状態が、10回の繰り返しにより、10×10=100効果になり完全に見えない(幽霊100)となる。

ここのフェードインは、ほかの画面のフェードイン・アウト(後に説明する trans 系イベントを使用するもの)とは全く関係がない。最初の旗ボタンによるアプリケーション開始時専用である。

初期化3:URL表示を消す

画像12

スクラッチには、単純型(数値、文字列)の順序付きコレクション「リスト」が唯一のデータ構造と呼べるデータ型として用意されている。

「リスト~を隠す」はそのリスト変数の内容を画面表示を消す、という意味だ。今回の解説最後で触れるが、このリストには他のサイトへのURLが入っていて、そのサイト紹介のために画面に「リスト Link を表示」することがある。画面に「表示」された変数は、プロジェクトを停止再開しても表示されたままなので、ここで必ず非表示にしている。

初期化の処理すべてが終わると、Transitions スプライトは次の状態になる。これが Transitions スプライトの intro モード画面での状態になる。

■ 表示している。「表示する」した状態。

■ 見えない。幽霊=100(パーフェクト幽霊)。

■ 常に一番手前に表示されている。

Transitions スプライト:2.  エラーがあった時に表示する処理。

Transitions スプライトは、ほかのコードで発生したエラーを表示する役割がある。次のスクリプトがその部分で少し長いが、難しいことはしていない。

大きく分けると4つの処理を順番に実行している。

画像16

一番最初の部分を拡大したのが次の写真だ。

画像17

Among Us Scratch では、何らかのエラーがでたら、スクリプトは failed イベントを送るルールになっている。エラーが出たら、とにかく failedイベントを送信すれば、Transitions スプライトが適切にエラー内容を「画面いっぱいに」表示してくれる。

エラー処理・表示の方法がある程度統一化されていれば、プログラムがエラー処理や表示コードだらけでぐちゃぐちゃになることがない。エラーハンドリングはコードを汚染しやすいのでこういった取り決めはとても大事だ。

Transitions スプライトのこのスクリプトは、failed イベントを受け取ったら、まずほかのスクリプトを止めて、動作中の処理が動き続けるのを回避する。エラーのような「何かしている最中に突然発生するもの」の処理では、エラー処理以外の動作をできるだけ止めることも大事なことだ。

その後に見た目の処理が続くのだが、実はこの部分が少しテクニカルで、Transitions スプライトのフェードアウト・イン処理のキモとなっている。コード順に少し詳しく見ていく。

画像46

■ 「幽霊」の効果=0にして、コスチュームが見えていて画面が真っ黒の状態にする(幽霊ではない)。

■ 「明るさ」の効果をー10づつしていき、最後は0にする。

まず、エラーが出たら幽霊効果を0=完全に見えている状態にしてコスチュームを表示する。常に最前面のスプライトなので、真っ黒のコスチュームが画面を覆う。

その後、明るさ効果を調整するが、その明るさについて、少し図解する。

「明るさ」は通常0で、100だと「真っ白」、ー100だと「真っ黒」になる効果だ。次の動画は100、ー100、0と切り替えてみたところ。

画像20

(動画は、コードをクリックしてその場で実行する、スクラッチの便利なデバッグ機能を使った)

エラーが発生したとき、たまたま別の真っ黒+メッセージを表示しているかもしれない。そういった場合でも、直前のメッセージは先の10回繰り返す処理で「明るさが10づつ減ってー100」になり消える。次はその場合を実験してみたものだ。

画像21

最初「何かエラー表示してる」が出ているが、別のエラーが発生したときは、いったん明るさをー100にしてメッセージを真っ黒にする。

この時、地は真っ黒だから、明るさがー100でも真っ黒のままで変化しない。このままコスチュームを「別のエラー」変えて新しいメッセージにしても、真っ黒のままだからわからないが、明るさを徐々に上げていくと、新しいコスチュームの「別のエラーが発生した」のメッセージが現れる。

「幽霊」を真っ黒い地のフェードアウト・フェードインに使用し、「明るさ」は中に表示している文字のフェードアウト・フェードインに使用する。面白いテクニックだと思う。

(明るさがー100なら真っ黒、というのをうまく利用しているが、地が真っ赤なフェードイン・アウトをしたいときはこの方法は使えない)。

フェードアウト処理の次は、エラーに応じたコスチュームを設定する。次の写真はその部分だ。

画像18

failed イベントを送信するときは、エラーの内容を「failed?」変数に設定してあれば、上のコードで適切なコスチュームが設定される。

例えば、最初の failed? = 1 のときは、コスチュームで紹介した no_longer_exist が表示される。

画像19

実際は、先の動画のように、この時点では明るさはー100=真っ黒なので文字は見えていない。真っ黒の地はそのまま画面に出ているので、背景やスプライトは隠されたままだ。

コスチューム設定したら、明るさを戻してコスチュームの内容をプレーヤーに見せる。

画像22

すでに表示されているので、ここの「表示する」コードは不要だが、過去に消したりしていた残滓かもしれない。その後、中途半端だが 1.1 秒待つ。ユーザーにじっくり読ませる時間とは言い難い気はするが、ここは重要ではなさそうなので気にしない。

最後は、再度明るさをー100まで10づつ変えて、表示しているメッセージだけフェードアウトする。

画像23

エラー内容を持つ変数 failed? を0にしている。failed? は failed イベントを送るときは必ず設定するルールだから、ここで0に設定することは意味がないように見える。

もしかしたら、failed? 変数が0でないならエラー表示中、のような判定用に使っていたことがあるのかもしれないが...。

スクラッチでは、イベント送信に対して、ブロック(プロシージャ・関数)のような引数強制をできないのがツライ。妥協して、上の0設定コードはそのままに、failed? 未設定で値が0だったら「不明なエラー」のようなコスチュームを表示して、ルール通りに failed イベントを使わなかったことがわかるようにするのは良い方法かもしれない。

実行前に約束事をきちんと確認できないプログラミング言語では、自分で作ったプログラミングルールを自分で破ってしまうことが多い。この点でスクラッチはあまり好きなタイプの言語ではないのだが、これは個人的な感想です。

Transitions スプライト:3. モード切替時のフェードアウト・フェードインの処理

Transitionsという名前の「移り変わり」「遷移」という意味どおり、Transitions スプライトの本業?とも言えるのが、このモード切替等に使用するフェードアウト・フェードインの処理だ。ゲームプレイ中もあちこちで遭遇する。

モードを切り替える処理は、前回のONLINEボタンの画面遷移やこの記事の冒頭で見たように、フェードアウトする trans1 イベントと、フェードインする trans2 イベントに分かれる。切替をする側のコードは次の形になる。

画像24

Among Us Scratch では、画面のモードをフェードアウト・インを使って切り替えるときは、必ずこのようにするルールとなっている。

trans1 イベントの処理

まず trans1 イベント「フェードアウト」を受け取るところを見る。

画像25

最初のコードは「表示する」だ。初期化後の Transitions スプライトは「表示する」しているので、「表示する」は不要そうに見える。しかし、trans2 イベントのフェードイン処理でスプライトは「隠す」されてしまうため、この「表示する」がないと、trans2 イベントを処理した後に再度 trans1 をする機会があってもスプライトが正しく表示されない。ちょっとややこしい。

次に、幽霊効果を10づつ減らしていく。ループが終われば 10 × -10 = -100 で真っ黒になり、フェードアウトは完了する。

この後、trans3 イベントを送って trans1 イベントの処理は終了する。trans3 は「特殊なモードのときの真っ黒な画面表示」をお願いするイベントだ。後程詳しく見ることにする。

trans1 イベントのこのスクリプトは全部終われば画面は真っ黒になっている。モードを切り替えるとき、イベントを「送って待つ」すれば、イベントを送った次のコードは「真っ黒の状態」で実行される。

画像27

trans2 イベントの処理

次の写真は、フェードアウトを始める trans2 イベントのスクリプトだ。

画像26

こちらもまず「表示する」が、trans2 を送る時点で Transitions スプライトはフェードアウトで真っ黒表示の状態だから、この「表示する」コードにはあまり必要性が感じられない。

続いて、「幽霊」効果と「明るさ」効果をセットでフェードイン処理をする。次第に Transitions スプライトは見えなくなっていく。「明るさ」がー100になることで、真っ黒の上に表示されているメッセージ文字は、地の真っ黒に近づきながら「幽霊」で一緒に消えていく。

見えなくなったところで「隠す」をする。見えなくなっているのでこのコードは不要なのだが、ここで「隠す」してしまうために、Transitions スプライトのコードはあちこちで「表示する」が必要になっている。必要なんだろうか...。

また、先ほどエラー処理で見たように、幽霊効果で「真っ黒の地の部分」の可視性を管理しているのに、「表示する/隠す」でもコントロールするのは二重管理となっている。その点でもあまり良い実装とは思えない。

スクリプトの最後に、コスチュームを normal (ただの真っ黒な絵)にしている。この後見ていくが、フェードアウト中にメッセージの描かれた別のコスチュームを表示することもあるので、ここで元の状態に戻しておかないと、後で trans1 がかかったときに、メッセージのあるコスチュームが見えてしまう。

trans3 イベントの処理

trans1 イベントのスクリプトは、フェードアウトして画面が真っ黒になった後、最後に trans3 イベントを送っていた。

画像28

trans3 は Transitions スプライトの別のスクリプトで受け取られ、特別な画面モードのときに真っ黒の上にメッセージを表示するように仕込まれている。

少し細かいが重要な動作として、trans 3 を送ったところで trans1 イベントの処理は完了しているので「trans1 を送って待つ」というコードはここまでしか待たないという点だ。「trans1 を送って待つ」は trans3 以降の処理は放置する。

次の写真は、その trans3 を受け取った後のスクリプトで、特定のモードのときだけ、メッセージが描かれたコスチュームを表示している。

画像30

最後の青い枠内のコードは画面モードが cng = Creating new game (ホストになって新しいゲームルームを立てるモード)で表示される。次の動画は、cngモードで「Creating new game」と出ている画面だ(わかりやすいように、modus 変数を表示している)。

画像30

trans3 イベント最初の処理部分は次の写真の4コードある。モードにかかわらず実行される部分だ。

画像31

コードはそれぞれ順に次の処理をする。

■ 画像効果をなくす:「幽霊」や「明るさ」等の効果をすべてリセットして、なかったことにする。trans1 イベント処理ですでに真っ黒のコスチュームが表示されている状態なのでリセットしても特に変化はない

■ 表示する:スプライトを表示する。trans1 イベント処理ですでにコスチュームを表示しているので更にやっても特に変化はない

■ 明るさの効果を-100にする:コスチュームが真っ黒だけではなく文字がかかれているならそれも含めて真っ黒にするが、周囲を確認したところあまり役に立っていないように見える

0.5秒待つ:上で設定した状態で少し待つ。

最初の2コード、「画像効果をなくす」と「表示する」が必要性に、はなはだ疑問が残る。何度か修正や作り直しを経た歴史的な結果で仕方ないかもしれないが、「とりあえず」「念のため」のコードが Transitions スプライトには多く見受けられる。余計な副作用をひきおこしたり、そのようなコードをバラまきすぎて「消したはずの処理がまた現れた!」バグの原因にもなりかねないのであまり感心はできない

明るさの効果を-100にするコードも、通常の画面切り替えなら真っ黒だけなので不要だし(真っ黒はいくら明るさを小さくしても真っ黒)、この後にメッセージのあるコスチュームを設定する場合は、そちらで同じことをしているので、やっぱり不要なコードに見える

最後の 0.5 秒待つコードに関しても、待っているのが「真っ黒の状態」だから、ぶっちゃけプレーヤーにとっては「ちゃんと動いてるのこれ?」という疑問を抱かせる時間を増やしているだけではないだろうか。某コンシューマーゲーム等は真っ黒の画面が~秒以下、というルールを守らないと発売させてもらえなかったりする。

この4コードを削除してテストプレイしてみたが特に不具合らしきものが見つからなかったし、画面遷移が少し速くなって気持ちよくなったようにすら見える。どなたかこの4コードについて「実はこのようなケースが」等の知見おもちでしたらご教示ください。

感心しないコードに説明が長くなってしまったが、trans3 イベントを受けるスクリプトは引き続いて、画面が joining モードと cng モードのときだけ特別な処理をする。joining モード部分を抜き出したのが次の写真のコードだ。

画像32

これまでの実装解析の知見の上に立てば、このコードはシンプルでわかりやすい。コスチュームを目的のものにしたうえで、「明るさ」効果を使って描かれているメッセージをフェードインして表示している。「幽霊」効果は変化せずコスチューム自体は表示したままなので、画面は真っ黒のままだ。

Transitions スプライト:4. 特別な画面用のエラー表示。

Transitions スプライトは、failed イベントを使ったようなエラー表示の他にも、特別な画面を表示するスクリプトがいくつか用意されている。

crashed イベントを受け取った時の処理

画像33

「クラッシュ」とか名前からして恐ろしい感じを受けるが、実際中身もなかなかすごい。要するに「コスチュームを crashed2 にしたうえで、スプライトどころかプロジェクト全体の何もかも止める」(最後が「すべてを止める」になっている)。

crashed2 コスチュームは次の写真のような絵だ。きっと、もうどうにもならない状態で発生するエラーなのだろう。

画像34

lag_detected イベント

lag_detected イベントは、名前からするに通信品質が悪くてプレイに適さないような状態のときに送られるイベントだろう。

画像35

このコードはほぼ crashed と同じだが、表示するコスチュームが違って too much lag になっている。コスチュームは次の写真だ。

画像36

「ラグがひどすぎる! TurboWarp に行ってもっとラグ無しでプレイしてくれ」とうメッセージで、これもこれ以上プレイできなくなる。

余談だが、TuroboWarp はスクラッチとほぼ同じ内容のサービスで、スクラッチよりも処理速度が速いことを売りにしている。

また、Among Us Scratch を遊ぶのに必須の「クラウド変数」は、スクラッチにある程度熟練して「スクラッチャー」というクラスにならないと使えないので Among Us Scratch も「スクラッチャー」でなければ遊べない。一方、TurboWarp は初めからクラウド変数を使えるので、Among Us Scratch を遊ぶだけなら TurboWarp の方が快適かもしれない。

最後に「リスト Link を表示する」しているが、この Link にはその TurboWarp の Among Us Scratch へのリンクが入っていた。表示すれば次の画面の下部のところでURLのコピペができるので、すぐそちらへ移動できる。

画像40

turbo_mode_detected イベント

turbo_mode_detected イベントは、第一回の背景スクリプトの解析で見つけたイベントで、スクラッチのデバッグ用に高速動作させる turbo modeだと送られるイベントだ。

このイベントを受けるのは、 Transitions スプライトの次のスクリプトだ。

画像38

先の crashed イベントのスクリプトとほぼ同じアプリケーションを完全停止させるコードだがコスチュームだけ違っている。コスチュームは次の絵だ。

画像39

tick3 イベントを受け取るスクリプト

tick3 イベントは、ここまでこの解析 note では未見のイベントだが、それを受けている次のスクリプトも、見ただけでは何をしているかさっぱりだ。

画像37

特に「スタンプ」が怪しい。

スタンプは、スプライトや背景とは異なり、プログラムで画面に絵を直接「描く」。「ペン」と呼ばれるものの機能の一つで、スプライトにつかうと、スプライトの絵がそのまま画面に残る。ただの絵として残るだけで、スプライトではないので位置や色を変えたり、コードを動かすことはできない。

次の動画は、位置を変えながら5回スタンプしてみた例だ。残像のように残っているキャラクタ「アビー」は、スタンプで描かれたものなのでスプライトではない。

画像43

すくなくとも、Among Us Scratch では「ペン」を使うので、描いたものが不要になったら「全部消す」ですべて消さなければならないことはわかる。第一回で解析した背景の最初のコードで『全部消す』しているのは意味があったのだ。

ただ、tick3 イベントについては、結局よくわからないので保留にする。

clear イベント

clear イベントを受け取ったら、コスチュームを完全に表示(幽霊効果100)する。ただし、それしかわからないので、これも保留する。

画像41

set_volume イベント

set_volume イベントを処理するスクリプトは Transitions スプライトにも存在した。

画像42

このスクリプトも、背景タイトルの Among Us スプライトintro モードのボタンと同様、表示状態にかかわらず、イベントがあれば必ず動作する。もう4つ目だが、これだけあると実は必要な理由があるのではないだろうか。「正しく動作するバグ」ではないと証明される日がくるだろうか。

全く謎のコード

画像44

イベントだけのコードと、なんのイベントにもぶら下がっていなくて絶対に実行されないコード。

どちらも、通常プレイ中はまったく役に立たない。後者のコードをクリックして強制的に実行すると次の画面になる。

画像45

Among Us Scratch はクラウド変数を使うので、プレーヤーは必ず Scratcher というビギナーではないスクラッチアプリケーション作成経験がなければならない。それを検出して表示するスクリプトのようだが、動かないスクリプトであれば意味がない。

後者のほうには「is compiled?」という謎の式もある。ピンク色の六角形はブロックで作られた「関数」なのだが定義がないので、「昔作ったけど定義本体は消して名前だけ残った」状態。これは絶対バグなのだが、仮に以前は動いていたとして「クラウド変数が使えなくてコードがコンパイルできないことを検知」なんてできるんだろうか?

まとめ:高度な技術とゴミコードのはざま

Transitions スプライトは、いろいろ興味深いものがあった。

■ 1つのスプライトで、画面のフェードインアウトと、処理中の通知やエラー表示の2つの効果を担う。

■ フェードアウト時の地は「幽霊」効果、地の上に表示されるメッセージは「明るさ」効果で、別々にコントロールしている。

■ アプリケーションのエラー表示処理がまとめてここに実装されている。どこからでもイベントを送るだけでエラー画面が出せる。

■ 「念のため」のようなコードや、可視性を「幽霊」「表示・隠す」の2つの方法で実装するなど、あまり感心できない実装があった。

■ 動かないコード、動いてるだけでおかしいコード(set_volumeイベント)、等のコードは Transitions コードにもあった。

玉石混交なコードの印象だが、イベントというごく単純な抽象的仕組みを挟んで、モードの切り替えと画面の動作がお互いを一切知らずに連動できるようにに作られているのは素晴らしいと思う。といってもスクラッチで、スプライトや背景の間でなんらかの連携をする方法は、変数を除けばイベントしかないですが...。

次の記事

Among Us Scratch の解析5:ゲームの選択


この記事が気に入ったらサポートをしてみませんか?