スクラッチに挑戦している皆さん、どうも!スクラッチコーチです。
このチュートリアルはオンラインゲームの作り方を通して作ったスプライト「クラウドプレイヤー」を使うことを前提にしているよ。まだ作ってないという人は先にオンラインゲームの作り方を見るか、前のチュートリアルに行ってスプライト「クラウドプレイヤー」をバックパックに入れておこう!
- ① クラウド変数の使い方
- ② エンコードする
- ③ デコードする
- ④ マイナス値に対応する
- ⑤ バッファリングを実装する
- ⑥ 別プレイヤーを検知する
- ⑦ プレイヤーを管理する
- ⑧ クローンを使おう
- ⑨ スケールアップする
- ⑩ 退場処理を作る
- ⑪ 自作ゲーム「鬼ごっこ」を作る
- ⑫ MMO鬼ごっこに改造する
- ⑬ クラウド変数でユーザー名を共有する方法 (いまここ)
ちなみにこのチュートリアルは⑩退場処理を作るまで終わってれば作れるよ。
今回の目標「マウスを乗せたらユーザー名が表示される」
数字しか共有できないクラウド変数に、強引に文字を入れて共有する方法を実装していくぞ。
↑この警告を読んでね。でも今回はユーザー名を共有するために文字を仕込むから、規約違反にはならないよ。安心してほしい。
最終的なゴールとしては他のプレイヤーにマウスを乗せたら、そのプレイヤーのユーザー名が表示されるようにしていきたいと思ってる。こんな感じ↓
ユーザー名を共有できれば、スコアなども一緒に共有してクラウドランキングみたいなものを作ったりすることも可能になるから、やりたいことがもっともっと実現できるようになる!
スク友やリア友と一緒にプレイしてお互いを認識できたりもするし、楽しいことが広がっていく予感がヒシヒシだ!
ってことでコーディングしていこうか!
まず復習がてら作戦を把握する
文字の共有をするにあたって、2つブロック定義を追加する予定。その前に現在の処理とデータ構造を復習しておこうと思う。
復習
すでにスプライト「クラウドプレイヤー」の処理を把握できているなら、ここは飛ばしてもOKだ。
クラウド変数を受信する流れ
今まで作ったスプライト「クラウドプレイヤー」を見てみると「順番にデコードする」というブロック定義があるよね。
このブロック定義ではクラウド変数経由で共有されたデータ「エンコード文字列」の中身を1つずつ読み解いて変数「値」に結果を入れるんだったね。
この変数「値」をいろいろな用途で使っていくっていうのがおおざっぱな流れだね。
「順番」が分かりにくい
現在は共有するデータが少ないので、1番目はプレイヤーUID、2番目はX座標、3番目はY座標と憶えておける。
でも(オンライン鬼ごっこで実装したように)データ数が増えていくと「順番」なんだっけ?となる。
しかもスプライト「クラウドプレイヤー」では遅延をなくすためにバッファリングという技巧を施してあるので、エンコード文字列の中身は単純に1番2番という順番では表すことができないよね。
つまり、エンコード文字列には2種類のデータが格納されていると言える。
↑このように最初にリピートしないデータ(仮に固定データと呼ぶ)と、そのあとにリピートするバッファリングデータが続くよね。
順番にデコードする処理はどこで実行されるか
2種類のデータがエンコード文字列に格納されていることを踏まえて、ブロック定義「順番にデコードする」はどこで実行されているか再確認しておこう。
クラウド変数を受信する
次のプレイヤーデータを移す
クローンティック
2種類のデータの呼び出し方が違う
気づいている人もいると思うけど、固定データとバッファリングデータは呼び出される場所が明確に違う。
- 固定データであるプレイヤーUIDは、ブロック定義「クラウド変数を受信する」と「次のプレイヤーデータを移す」でデコードされている
- バッファリングデータはブロック定義「クローンティック」でデコードされている
このような違いがあるってことを認識しておこう。
今回の作戦内容
で、本題だ。
今回入れたいユーザー名は固定データとバッファリングデータのどっちかな。
ユーザー名はとくに変わることもないのでわざわざリピートして何回も共有する必要はないから、固定データだね。
視覚化するとこんな感じにしたい↓
ということで、そろそろコーディングしていこうか。
改修を1つ
本題をコーディングする前に、一箇所だけ改修しておこうと思う。
ブロック定義を編集する
ブロック定義「順番にデコードする」を編集して、文字「//」と引数「メモ」を追加してほしい。
ブロック定義の実行するとこにデータ名を追加する
このブロック定義が使われている箇所で、いったいなんのデータをデコードしようとしているのか書き込んでおこう。
クラウド変数を受信する
次のプレイヤーデータを移す
クローンティック
この引数はとくに使い道はないんだけど、こうすると後日見返したときに最高に分かりやすいと思わない?
ちなみにスラッシュを2つ追記したのは、Javascriptなどのプログラミングではメモを書くときにはスラッシュを2つ書いてから書くというルールがあるからなんだ。それをなぞってみた。
文字列をエンコードする
いまあるブロック定義「エンコードする」は、数値を取り扱うことはできても文字列を取り扱うことはできないよね。
そのため文字列をエンコードする仕組みを、数字のエンコードとは別に作っていく必要があるんだ。
準備
じゃあ新しく文字列をエンコードするために以下の2つの重要なコーディングをしていくよ。
- あらかじめエンコードできる文字一覧を保持したリスト
- 文字列をエンコードする専用のブロック定義
リストを作る
文字一覧というリストを作るよ。このリストはゲーム開始後に変更されることはないから、「変わらない変数」という意味で「定数」と呼ばれる。でもスクラッチだと定数という概念はないから、「これは定数として扱う」と明示するために接頭語に■を付けておこう。
初期化する
このリストを初期化する。このリストには想定される英数字をすべて入れていくんだけど、95文字あるから1つずつ手作業で入れるのは手間すぎるんだ。
だからトリッキーだけど初期化用のループを1つ作っておくよ。
リストの中を削除するところから始める
どこか適当な場所に次のブロックを置いてみて。
緑の旗が押されたとき、とかは不要だよ。クリックして実行することになるから。
リストの1番目に文字をズラッと入れる
続けて次の文字列をリストに追加しよう。1文字目は半角の空白だから注意。しっかり全文字コピーしてね。
!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
↑をコピペして次のようにブロックを置いてね。
ループを置こう
文字数の数だけループさせる
リストの1番目にズラッと追加した文字の数だけ繰り返す条件式を作りたいから、次のブロックを用意して↓
これをループの条件式に当てはめよう。
先頭の文字から順番にリストに追加していく
このループの中で、先頭の文字から順番に追加していくよ。
先頭の文字を取得する方法は次のブロックで実現できる。
リストには1つだけデータが入った状態だよね。だから「リストの長さ」というブロックからは「1」が返ってくる。
リストの1番目にはさっきのズラッと長い文字列が入ってて、最初の文字は空白だから、↑このブロックが返すのは空白文字になる。
これをリストに追加してみよう。
できあがったブロックを、ループ内で実行するように配置しよう。
これでリストの長さはどんどん増えるよね。最初は1だったけど、1つ追加されたあとは2になるから、次は2文字目である「!」が取得される。それも追加すれば長さは3になるから……っていう感じで結果的に全文字追加される仕組みなんだ。
最後にリストの1番目を消す
ブロック全体をクリックして実行する
この一連のブロックたちはクリックすれば実行できる。ためしにクリックしてみて。結果はこうなるはず↓
95文字すべて入ってればOK!このブロックは念のため消さないでどこかに置いておこう。
1文字ずつの定数リストを初期化するときに便利な方法だからバックパックしておいてもいいかも。
この方法じゃなくてもテキストファイルをリストにインポートする方法もあるし、グリフパッチさん達が作ってるスクラッチアドオンを使っている人なら直接リストにデータをコピペしたりも出来る。
ブロック定義を作る
名前は「文字列をエンコードする」だよ。あとは分かりやすく引数名や、実行後に結果が格納される変数名を書いておくのも吉!
文字列をエンコードする作戦
さぁ、このブロック定義の中身を作り込む前に何をどう作るのか作戦を共有しておきたい。
まず前提として引数「文字列」にはユーザー名が渡される予定だ。
ここではサンプルとして僕のユーザー名であるok-scratchを使うね。
- 文字列の長さをカウントする(ok-scratchは10文字)
- 10回以下の処理を繰り返す
- ok-scratchの次の文字を取得する(最初は1文字目、つまり「o」
- 「o」が文字一覧リストの何番目に格納されているのかを調べる(「o」はリストの48番目)
- 48という結果を変数「値」に追記する
- 最後に文字数の長さ(10)と変数「値」を繋げて変数「エンコード文字列」に追記する
ちょーっと意味不明な感じかもw
しっかり把握してから実装に移りたいので、以下で視覚化して解説もしておく!
① 文字列の長さをカウントする
ok-scratchという文字なら10文字だよね。
これを取得すると同時に、ついでにエンコード文字列にも追記しておく。
10は1と0の2文字だから、エンコードすると210として格納される。
② 文字ごとにリスト内の格納場所を調べる
次にok-scratchというユーザー名を1文字ずつ調べる。何を調べるかというと、各文字が文字一覧リストのどこにあるかを調べる。
1文字ずつ文字一覧リストと照合して調べる。10文字だから10回。
実際のブロックを使って照合のイメージをつかもう
単純化するとこんな感じで照合する↓
③ 文字数と各文字の格納場所をエンコード文字列に追記する
最終的に10という長さのデータと、1文字ずつ調べた格納場所を全部くっつけてエンコード文字列に追記する。
でこのエンコード文字列をクラウド変数に渡せば送信は完了!
ここまでが今から作るブロック定義の中身だ。
よっし、一緒に手を動かしてみよう!
ちなみに読み取るときは、最初に先頭の10という数字を取得することで、このあとの10文字分のデータがひとかたまりの文字データなんだなと把握できる。そしてまた文字一覧と照らし合わせて、各数字がどの文字なのかを調べるんだ。まぁそれはもうちょい後でやるね。
コーディングする
作戦内容をコーディングしていこう!
まず文字列の長さをエンコードしてしまう
まずは引数で渡されてくる文字列の長さを調べる。そのためには実は新しい処理はいらない。すでにあるブロック定義「エンコードする」にそのまま文字列の長さを渡してあげればいい。
これでエンコード文字列には、例えばok-scratchなら、210という値が追記されたね。
変数「値」を初期化する
ブロック定義「エンコードする」内では変数「値」にデータを入れてるよね。
でも変数「値」はこのあと文字列用に使いたいからひとまず初期化しとく。
変数「_文字列インデックス」を作る
このあとループを作って行くんだけど、その中で1文字ずつカウントアップしていくための変数を用意しておく。いわゆるインデックスとして使っていく。
でもこの変数はここ以外で使わないから、そのことを明示するために接頭語にアンダーバーを付けておこうと思う。
初期化する
最初は1を割り当てておくよ。
1文字ずつ調べるためのループを作る
文字の長さだけ繰り返すループを設置しよう。
文字列の文字を取得する
文字列の文字を1文字ずつ取得するよ。要となる処理はこちら↓
次にこれで取得できた文字が、文字一覧リストの何番目に格納されているかを調べるよ。
こうすることでリストの何番目に文字があるかが取得できる!たとえばこんな感じ↓
ok-scratchの1番目の文字である「o」は文字一覧リストの48番目にある、っていう情報が取得できる。
あとはこれを変数に格納していきたい。
変数「文字一覧の何文字目か」を作る
そのための変数を新しく作るよ。
結果を格納する
この変数にさっきの結果を格納するよ。ちょっと長いけどこんな感じになる↓
必ず二桁になるように調整する
ここで新しい仕様を紹介する。文字一覧の何文字目か、という情報は必ず二桁になるようにしたい。
文字一覧には95文字が格納されているから、ほとんどのケースで二桁になる。ただし、もちろん1から9に格納されている値だけは一桁になってしまう。そこで1から9のときはゼロ埋め処理を行うようにする。
条件ブロックを追加する
1から9ならという条件式を作る
1から9なら、というのは10未満ならと言い換えることができるので、次のとおりに条件式を作ろう。
ゼロ埋め処理をする
1なら01になるように左側にゼロをつける処理を作るよ。
値に結果を追加していく
変数「値」に、変数「文字一覧の何文字目か」を追加していくよ。追加だから、元々の値にくっつけるように次のとおりにするよ。
文字列インデックスを加算する
ループの最後に変数「_文字列インデックス」に1ずつ変えよう。
こうすることで次のループ処理ではok-scratchのkが処理される、っていう感じでどんどん文字を調べていけるよ。
エンコード文字列に追記する
ブロック定義の最後の処理として、変数「値」を変数「エンコード文字列」に追記しよう。
よし、これで文字列のエンコード処理は完成だ!
ブロック定義を配置する
ブロック定義「クラウド変数を送信する」にて、プレイヤーUIDをエンコードした直後にユーザー名をエンコードするブロックを追加しよう!
テストしてみる
ちょっとテストしづらいけど、実行して変数の中身をスクリーンショットして調べてみる。
自プレイヤーUIDの後ろにしっかり210から始まる10文字分の文字データが格納されているぞ!
よーし。
文字列をデコードする
デコードする流れは次の通り。
- 文字の長さを調べる。
- 文字数の数だけ以下を繰り返す。
- 文字の格納場所を取得してリストと照合する
うん、エンコードに比べるとシンプルそうだけど、やっぱり文字で説明しただけだと意味不明だねw
作戦内容の解説
ということで同じく視覚的に解説したものを掲載しておくぅ!
① 文字の長さを調べる
まずはエンコード文字列から文字の長さを知るんだね。これは実はすでにあるブロック定義「順番にデコードする」で実現できちゃうから楽なんだ。
処理としては以下のようなイメージで文字数を取得するよ。
② 1文字ずつリストと照合する
1文字は必ず二桁で管理されているから、それを前提に文字数だけ実行されるループを作って、そこで1文字ずつ文字一覧と照合する。
そうして数字から文字への変換を実現させるのがデコード処理の本質的な部分だ。
コーディングする
よし、これを実装していこう!
ブロック定義を作る
ブロック定義「文字列をデコードする」を作ろう。
文字数を調べる
まずは何文字のデータなのかを調べる。それにはすでにあるブロック定義「順番にデコードする」を使えばOKだ!やっほぃ!
変数「_文字数」を作る
結果を格納しておく変数を作っておこう。
結果を格納する
変数「値」に入っている結果を、あらためて変数「_文字数」に格納しよう。
変数「値」を初期化しておく
文字数の数だけ繰り返すループを作る
二桁を1つの数字として取得する
文字の格納場所は必ず二桁で管理されているから、エンコード文字列から2つ数字を取得してくっつけよう。
1文字目はコレで取得できる↓
2文字目はコレで取得できる↓
この2つをくっつける↓
この結果を変数「文字一覧の何文字目か」にセットしよう。
文字一覧と照合して文字を特定する
文字の特定はこんな感じでいけるね!
変数「値」に追記していく
変数「エンコード文字の順番」をカウントアップする
今回は二桁ずつ取得ているので、2ずつ加算する。2って直接書くよりは動的に管理できるように以下の通りにしておく。
これを変数に加算する↓
よっし、これで完成。
マウスを乗せたらユーザー名が表示されるようにする
ここまでで文字列を共有する地盤は整った!実践的に使ってみたいので、マウスをクラウドプレイヤーに乗せたらユーザー名が出力されるような処理を作ってみよう。
ブロック定義を配置する
とりあえず文字列のデコード処理を実行するブロックを置こう。
これを実行するのはバッファリングデータを処理するところではなく、単発の固定データを処理するところがふさわしいね。
ブロック定義「次のプレイヤーデータを移す」の最後に追加しよう。
変数「クラウドプレイヤー名」を作る
結果を格納する
デコードした結果を変数に格納する。
クラウドティックに処理を追加する
クラウドプレイヤーには、ずっとループがあるわけではない代わりにブロック定義「クラウドティック」があるよね。
これはほぼずっとループと同じように機能するから、ここに処理を追加していきたいと思う。
マウスを乗せたらという条件ブロックを追加する
クラウドプレイヤー名を言う
この中では単純にクラウドプレイヤー名を言うようにしよう。秒数は0.5秒にしておくよ。
テストぉ!
OK!ついにユーザー名の共有ができたぜ。
まとめ
今回はエンコードとデコードを応用して文字列をオンラインでシェアできるように改造した!あらためてこのスプライトをバックパックにいれておけば、次からはカンタンに文字列をシェアできるオンラインゲームを作ることができるね!
ただし冒頭でも伝えたように自由に会話できるチャットを作ることは禁止されているから気をつけてね。
あと、もし日本語も追加したい場合は文字一覧リストが長くなって「1文字は二桁」という前提が変わるから、そのあたりも調整する必要があるよ。
まぁユーザー名を共有するだけなら日本語は入らないから問題ない!
ますますのオンラインゲーム制作を応援しているぜ。
- ① クラウド変数の使い方
- ② エンコードする
- ③ デコードする
- ④ マイナス値に対応する
- ⑤ バッファリングを実装する
- ⑥ 別プレイヤーを検知する
- ⑦ プレイヤーを管理する
- ⑧ クローンを使おう
- ⑨ スケールアップする
- ⑩ 退場処理を作る
- ⑪ 自作ゲーム「鬼ごっこ」を作る
- ⑫ MMO鬼ごっこに改造する
- ⑬ クラウド変数でユーザー名を共有する方法 (いまここ)
質問テンプレート(素早く3回クリックすると全選択できるのでコピーしよう)
・◯◯ ... 記事のどこまで実装が終わったのかを記入しよう。・□□ ... どんな問題が起きているのか、どういうときに起きるのか、具体的に書こう。
・共有済みURL ... たまに共有してない作品URLを書いてる人がいるけど、共有しないとこちらから確認できないからよろしくね。