スクラッチプログラミングに挑戦している皆さん、どうも!スクラッチコーチです。
前回はマイナス値に対応して一気に動きの同期確認まで進めたぞ!
下記動画が
前回までの
成果物だ。
改めてチェックしてみてほしい。タブ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では①の
次は④の
座標しか
受け
取ってないから、
欠落した②と③の
動きは
再現できないということだね。よし、
原因さえ
分かればだいたい
解決策も
存在するものだ。
ok-scratch
u003cpu003eちなみに1秒間に10回までしか送れないというのは、レッスン1で書いた「クラウド変数は同期するのに0.1秒のラグがある」というルールを言い換えただけだよu003c/pu003e
遅延の解決策はバッファリングにあり
問題をカンタンに
言うと「3
回に1
回しか
送れない」こと。なら1
回で3
回分送ればいいじゃん?っていうのが
解決策。くわしく
書くね。
上の
画像だとさ、①も②も③も
送ろうとするから
結局①しか
送れてない、っていう
状態になってるんだ。だからいっそのこと
全データを
毎回送るのは諦めて、①と②のデータもまとめて③の
時に
送るっていう
作戦で
行きたい。
ok-scratch
u003cpu003e給食当番で例えると、ご飯を配る時に1つずつ配るんじゃなくて、トレーに3つ乗せてから配ろうっていうイメージ。u003c/pu003e
①と②ではエンコードしたデータを
溜めておいて、③になったら(または④になったら)データをクラウド
変数1にセットするということだよ。そして、
この溜めてから送る手法がバッファリングという
技なんだ!
手を動かすぞ!
うっし、じゃあ
手を
動かしていくぞ!
プロジェクトのコピーを保存する
とりあえずプロジェクトのコピーを
保存しておこう。プロジェクトの
名前はそうだね……ここまでは「オンラインゲームの
作り
方1」にしておいて、ここからは「オンラインゲームの
作り
方2」とかにしたらいいんじゃないかな。もちろん
自分が
分かりやすい
名前で
問題ないよ。
スプライト名を「自プレイヤー」に変える
いまあるスプライトの
名前を「
自プレイヤー」にしようか。
スプライトを複製する
右クリックでスプライトを
複製しよう。
スプライト名を「クラウドプレイヤー」に変える
複製したスプライト
名は「クラウドプレイヤー」だ。これはクラウド
変数を
同期して
動く
用のスプライトだ。
今まで
言うところの
数字キー2を
押したときの
動きをする
用のスプライトみたいなものなんだ。
自プレイヤーを整理する
まずはスプライトの
選択を
自プレイヤーに
戻そう。
不要なコードを削除する
緑の
旗を
押した
時のコード
以外は、ほぼすべて
消すよ。
「数字の2キーが押されたとき」を消す
エンコードを消す
デコードを消す
「緑の旗がおされたとき」の一部を消す
これだけ
残す↓
めっちゃ
減ったw
自スプライトからメッセージを送る
イベント「クラウド - セットアップ」を作る
新しいイベントを
作るよ。イベントのメッセージのブロックから「
新しいメッセージ」を
選んで、
名前「クラウド - セットアップ」を
指定しよう。
配置する
最初に
送るようにするよ。
送るではなくて、送って待つブロックを
使うよ。
リスト「★送信用データ」を作る
リストを
用意しよう。これには
座標データを
入れる
予定だよ。
ok-scratch
u003cpu003e先頭に★が付いてるね。これは僕のマイルールなんだけど、「すべてのスプライト用」の変数やリストを作ったら必ず★を付けておくようにしてる。理由は分かりやすいからってだけ。★がなくても動きに違いはないよ。動画では★は付けてないし、どっちでもOK!u003c/pu003e
座標を追加してみる
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がクラウド
変数を
更新したことを
検知して、
新しいプレイヤーの
追加処理を
実現してみるぞ。それだけ
聞くと
前のチュートリアルで
実現したことと
同じだけど、
今回はバッファリングされたバージョンだからね!かつてあったカクカクは
極限まで
少なくなっているはずだ!
次回もすぐ
更新予定だから
待っててね!