スクラッチに挑戦している皆さん、どうも!スクラッチコーチです。
前回はマイナス値に対応して一気に動きの同期確認まで進めたぞ!下記動画が前回までの成果物だ。改めてチェックしてみてほしい。タブA(左)で更新されたクラウド変数1を、タブB(右)側で受け取って座標に割り当てることで動きの同期が行われている様子だ。
かーなーり、スムーズに同期されているけどまだ完璧ではないんだ。なぜって?それはスクラッチの仕様に原因があるんだ。
そのあたりを明らかにして、この遅延の解決策を実装するというのが今回の流れだ。これによってますますスムーズな同期が実現できる。いったいどこまでスムーズになってしまうんだ!
今回の目標「バッファリング」
せっかくスムーズな同期を作ったのになぜかまだカクカクしている……そんな頭痛の種を抱えている我々だが、大丈夫。頭痛といえばそう、頭痛にはバッファリングだ!(草)
スクラッチの仕様による遅延をバッファリングという技を使って解決するぞ。
必要なのはスクラッチへの情熱と優しさだ!なぜって?そりゃバッファリングの半分は優しさでできているからだ!(草2回目)
このバッファリングを使えば真の意味でクラウド変数たった1つだけで出来る同期処理が完成するんだ。よっしゃ、行こう!
遅延の原因は何?
手を動かす前に何をするのか、大まかな全体像を伝えておくね。
前回X座標とY座標をエンコードして1つにまとめて、クラウド変数1つで同期処理を実現するところまで完成したよね。これによってクラウド変数を2つ使っていた方法よりも倍以上のスムーズさを実現できた。素晴らしい。
これだけでもゲームの種類によっては十分だと思うけど、今回はトップクラスのスクラッチオンラインゲームの作り方を目指しているので、もっと極めて行くぞ!
問題が起きたら原因を調べる、これがプログラミングのベストプラクティスだ。
「ずっと」ループは1秒間に30回更新
さっそく原因究明するよ。次の画像をみてほしい。
スクラッチの「ずっと」ループでは基本的に1秒間に30フレーム更新されるっていう仕様なんだ。専門的に言うとfps30っていう状態。
つまりエンコードされたX座標とY座標の値が1秒間に30回ほどクラウド変数1にセットされるわけだ。
そしてこれはクラウド変数なので、全員と共有されるわけだけど、ここに罠がある。
クラウド変数は1秒間に10回更新
実はクラウド変数は1秒間に10回までしか同期されないんだ。
ずっとループでは1秒間に30回更新しているのに、クラウド変数は1秒間に10回しか同期されないってことだ。つまり3分の1しかデータが送れないわけだ……。どうにも嫌な予感がするよね。
次のイメージを見てみよう。
タブAでは30回分の座標データがあっても、クラウド変数の仕様でタブBには10回分しか届かない。そのため上のイメージだと②と③のデータは欠落してしまうことになる。これがカクカクが残ってしまう原因になっているんだ。
つまり、タブBでは①の次は④の座標しか受け取ってないから、欠落した②と③の動きは再現できないということだね。
よし、原因さえ分かればだいたい解決策も存在するものだ。
ちなみに1秒間に10回までしか送れないというのは、レッスン1で書いた「クラウド変数は同期するのに0.1秒のラグがある」というルールを言い換えただけだよ
遅延の解決策はバッファリングにあり
問題をカンタンに言うと「3回に1回しか送れない」こと。なら1回で3回分送ればいいじゃん?っていうのが解決策。くわしく書くね。
上の画像だとさ、①も②も③も送ろうとするから結局①しか送れてない、っていう状態になってるんだ。だからいっそのこと全データを毎回送るのは諦めて、①と②のデータもまとめて③の時に送るっていう作戦で行きたい。
給食当番で例えると、ご飯を配る時に1つずつ配るんじゃなくて、トレーに3つ乗せてから配ろうっていうイメージ。
①と②ではエンコードしたデータを溜めておいて、③になったら(または④になったら)データをクラウド変数1にセットするということだよ。そして、この溜めてから送る手法がバッファリングという技なんだ!
手を動かすぞ!
うっし、じゃあ手を動かしていくぞ!
プロジェクトのコピーを保存する
とりあえずプロジェクトのコピーを保存しておこう。プロジェクトの名前はそうだね……ここまでは「オンラインゲームの作り方1」にしておいて、ここからは「オンラインゲームの作り方2」とかにしたらいいんじゃないかな。もちろん自分が分かりやすい名前で問題ないよ。
スプライト名を「自プレイヤー」に変える
いまあるスプライトの名前を「自プレイヤー」にしようか。
スプライトを複製する
右クリックでスプライトを複製しよう。
スプライト名を「クラウドプレイヤー」に変える
複製したスプライト名は「クラウドプレイヤー」だ。これはクラウド変数を同期して動く用のスプライトだ。今まで言うところの数字キー2を押したときの動きをする用のスプライトみたいなものなんだ。
自プレイヤーを整理する
まずはスプライトの選択を自プレイヤーに戻そう。
不要なコードを削除する
緑の旗を押した時のコード以外は、ほぼすべて消すよ。
「数字の2キーが押されたとき」を消す
エンコードを消す
デコードを消す
「緑の旗がおされたとき」の一部を消す
これだけ残す↓
めっちゃ減ったw
自スプライトからメッセージを送る
イベント「クラウド - セットアップ」を作る
新しいイベントを作るよ。イベントのメッセージのブロックから「新しいメッセージ」を選んで、名前「クラウド - セットアップ」を指定しよう。
配置する
最初に送るようにするよ。送るではなくて、送って待つブロックを使うよ。
リスト「★送信用データ」を作る
リストを用意しよう。これには座標データを入れる予定だよ。
先頭に★が付いてるね。これは僕のマイルールなんだけど、「すべてのスプライト用」の変数やリストを作ったら必ず★を付けておくようにしてる。理由は分かりやすいからってだけ。★がなくても動きに違いはないよ。動画では★は付けてないし、どっちでもOK!
座標を追加してみる
X座標とY座標をリストに追加してみよう。
テストする
これで動かすとどうなるかな?
うわ!リストの長さがどんどん増えていく!これはバグる予感がヒシヒシするね!赤いボタンを押して止めておこう。
でも安心してほしい!この座標データはずっと保持しておく必要はなくて、クラウド変数に渡したら過去データは不要になるわけだから、その都度消すようにすれば大丈夫。やってみよう。
イベント「クラウド - ティック」を作る
今度はループ内で1フレームごとに送信されるメッセージ「クラウド - ティック」を作ろう。
配置する
よし、このままでは何も変わらないけど、とりあえず次に「クラウドプレイヤー」側を整えよう。
クラウドプレイヤー側を整える
ではスプライトを切り替えよう。
不要なコードを削除する
こっちも不要なコードは消していくぞ。
緑の旗がおされたときを消す
数字キー2が押されたときも消す
エンコードとデコードだけ残す
この2つは残しておこう!
メッセージ「クラウド - セットアップ」を受け取る
続けてコーディングしていこう!まずは「クラウド - セットアップ」の方から行くぞ。
初期化処理を作る
ここで最初に行われる初期化処理を作っていくよ。
まず隠す
とりあえずスプライトを隠しておこう。
過去データを消す
さっそくだけど過去データを空にしておこう。セットアップし直すから過去データは一切不要だ。
よし、とりあえずこれでOKだ。
メッセージ「クラウド - ティック」を受け取る
次にクラウド - ティックの受け取り処理も作ろう。これはスプライト「自プレイヤー」のループ内で実行されるから、1秒間にだいたい30回くらい飛んでくるメッセージだね。
でも僕らの作戦としてはこのメッセージは3回または4回に1度だけクラウド変数にセットして、それ以外のときはデータをためるバッファリングを行うってことだったね。そのあたりをここで実装していくよ。
変数「クラウドティック」を作る
何回目のメッセージ「クラウド - ティック」を受け取ったのかを管理するために同名の変数を作っておくよ。
初期化する
メッセージ「クラウド - セットアップ」のところに初期化処理を追加しておこう。
加算処理をする
メッセージ「クラウド - ティック」のところでは1ずつ加算するようにしよう。
ブロック定義「同期する」を作る
3回か4回送ったら同期するっていう処理をブロック定義にしてまとめていくよ。
条件分岐ブロックを追加する
もしも変数「クラウドティック」が指定した回数に達していたら、っていう条件を作りたい。そんなときも「もしも」ブロックだね。
条件式を作る
さて、演算はどうしようか。やり方はいろいろあるけど今回は剰余演算子を使っていこう。「割った余り」を調べる演算子のことだよ。
これだね。空欄にブロックをはめていこう。こんな感じ↓
これの解が0より大きいときはまだデータを溜める段階ってこと。
たとえば「回数」が4なら、クラウドティックが1なら1÷4の余りは1だからゼロより大きい。2,3も余りがでる。4÷4のときに余りがゼロになるね。
これを条件式として使おう。
処理を止めておく
とりあえず処理を止めておけばOK。
リストを消す
そして色々上手く行った後は改めてリストを消すようにしておくぞ。これはテスト用だからすぐ修正するけどね。
ブロック定義を呼び出す
ではメッセージを受け取った時にこのブロック定義を呼び出そう。引数には4を指定しておくよ。
テストする
リストの長さに注目!
よし、だいたいいいね!精度としては十分だ。
エンコードする
もちろん座標をエンコードして渡していくのが目的だから、このままでは終われないね。こっからが本番だ。
テスト用のブロックを消す
リストデータを消すところはいったん消してOK。
変数「エンコード文字列」を初期化する
消した場所に変数「エンコード文字列」の初期化処理を置こう。空白で初期化するよ。
リストの中身を全部エンコードするループを作る
リストの長さを使ってループブロックを作ろう。
ループにはめる↓
これを追加するぞ。
リストの先頭をエンコードしていく
このループ内でブロック定義「エンコードする」を呼び出そう。
引数にはリストの1つ目をハメる。
これを入れよう。
先頭を消す
直後に1つ目のデータを消してしまおう!
ちょっとトリッキーだけど、これでどんどん先頭がエンコードされていくんだ。リストの1つ目をエンコードした後にリストの1つ目を消したら、自然と2つ目のデータが先頭に来るからね!
クラウド変数1を更新する
最後にクラウド変数を更新しよう!
テストする
さぁどうなるかな。
よぉし!クラウド変数が次々と更新されているね!さっきまでよりも長くなっているのがバッファリングした分を一気にエンコードしている証だね。
次回へ
今回はここまでにしておこう!バッファリングという難しい仕様を実装することに成功したね。
今回やったことをまとめると次のようになるよ。
- スプライトを2つに分けて
- 自プレイヤー側からは「ずっとループ」が1フレーム進むごとに、「★送信用データ」に座標データを追加して「クラウド - ティック」というメッセージを送った
- クラウドプレイヤー側では「クラウド - ティック」を受け取って、4フレームごとに「★送信用データ」をエンコードしてクラウド変数1にセットした
よしよし、順調だ。次回は別のタブでも同じプロジェクトを動かしてみよう。タブA側でタブBがクラウド変数を更新したことを検知して、新しいプレイヤーの追加処理を実現してみるぞ。それだけ聞くと前のチュートリアルで実現したことと同じだけど、今回はバッファリングされたバージョンだからね!かつてあったカクカクは極限まで少なくなっているはずだ!次回もすぐ更新予定だから待っててね!
- ① クラウド変数の使い方
- ② エンコードする
- ③ デコードする
- ④ マイナス値に対応する
- ⑤ バッファリングを実装する (いまここ)
- ⑥ 別プレイヤーを検知する
- ⑦ プレイヤーを管理する
- ⑧ クローンを使おう
- ⑨ スケールアップする
- ⑩ 退場処理を作る
- ⑪ 自作ゲーム「鬼ごっこ」を作る
- ⑫ MMO鬼ごっこに改造する
- ⑬ クラウド変数でユーザー名を共有する方法