スクラッチプログラミングに挑戦している皆さん、どうも!スクラッチコーチです。
このチュートリアルはオンラインゲームの
作り
方を
通して
作ったスプライト「クラウドプレイヤー」を
使うことを
前提にしているよ。まだ
作ってないという
人は
先にオンラインゲームの
作り
方を
見るか、
前のチュートリアルに
行ってスプライト「クラウドプレイヤー」をバックパックに
入れておこう!
ok-scratch
u003cpu003eちなみにこのチュートリアルはu003ca href=u0022https://scratch.coach/lesson/how-to-make-others-leave/u0022u003e⑩退場処理を作るu003c/au003eまで終わってれば作れるよ。u003c/pu003e
今回の目標「マウスを乗せたらユーザー名が表示される」
数字しか
共有できないクラウド
変数に、
強引に
文字を
入れて
共有する
方法を
実装していくぞ。
u003cpu003eここでu003cstrongu003e超重要な警告u003c/strongu003eをしておく!u003c/pu003eu003cpu003eスクラッチではクラウド変数を使ってu003cstrongu003e自由に会話ができるチャットを作ることを規約として禁止u003c/strongu003eしています。絶対に避けましょう。詳しくはu003ca href=u0022https://ja.scratch-wiki.info/wiki/%E3%82%AF%E3%83%A9%E3%82%A6%E3%83%89%E3%83%81%E3%83%A3%E3%83%83%E3%83%88%E7%A6%81%E6%AD%A2%E4%BB%A4u0022 target=u0022_blanku0022 rel=u0022noreferrer noopener nofollowu0022u003eクラウドチャット禁止令u003c/au003eを参照してください。u003c/pu003e
↑この
警告を
読んでね。でも
今回はユーザー
名を
共有するために
文字を
仕込むから、
規約違反にはならないよ。
安心してほしい。
最終的なゴールとしては
他のプレイヤーにマウスを
乗せたら、そのプレイヤーのユーザー
名が
表示されるようにしていきたいと
思ってる。こんな
感じ↓
ユーザー
名を
共有できれば、スコアなども
一緒に
共有して
クラウドランキングみたいなものを作ったりすることも可能になるから、やりたいことがもっともっと
実現できるようになる!スク
友やリア
友と
一緒にプレイしてお
互いを
認識できたりもするし、
楽しいことが
広がっていく
予感がヒシヒシだ!ってことでコーディングしていこうか!
まず復習がてら作戦を把握する
文字の
共有をするにあたって、2つブロック
定義を
追加する
予定。その
前に
現在の
処理とデータ
構造を
復習しておこうと
思う。
復習
すでにスプライト「クラウドプレイヤー」の
処理を
把握できているなら、ここは
飛ばしてもOKだ。
クラウド変数を受信する流れ
今まで
作ったスプライト「クラウドプレイヤー」を
見てみると「
順番にデコードする」というブロック
定義があるよね。
このブロック
定義ではクラウド
変数経由で
共有されたデータ「エンコード
文字列」の
中身を1つずつ
読み
解いて
変数「
値」に
結果を
入れるんだったね。
この
変数「
値」をいろいろな
用途で
使っていくっていうのがおおざっぱな
流れだね。
「順番」が分かりにくい
現在は
共有するデータが
少ないので、1
番目はプレイヤーUID、2
番目はX
座標、3
番目はY
座標と
憶えておける。でも(
オンライン鬼ごっこで実装したように)
データ数が増えていくと「順番」なんだっけ?となる。しかもスプライト「クラウドプレイヤー」では
遅延をなくすために
バッファリングという技巧を施してあるので、エンコード
文字列の
中身は
単純に1
番2
番という
順番では
表すことができないよね。つまり、エンコード
文字列には2
種類のデータが
格納されていると
言える。
↑このように
最初にリピートしないデータ(仮に固定データと呼ぶ)と、そのあとにリピートするバッファリングデータが続くよね。
順番にデコードする処理はどこで実行されるか
2
種類のデータがエンコード
文字列に
格納されていることを
踏まえて、ブロック
定義「
順番にデコードする」はどこで
実行されているか
再確認しておこう。
クラウド変数を受信する
次のプレイヤーデータを移す
クローンティック
2種類のデータの呼び出し方が違う
気づいている
人もいると
思うけど、
固定データとバッファリングデータは
呼び
出される
場所が
明確に
違う。
- 固定データであるプレイヤーUIDは、ブロック定義「クラウド変数を受信する」と「次のプレイヤーデータを移す」でデコードされている
- バッファリングデータはブロック定義「クローンティック」でデコードされている
このような
違いがあるってことを
認識しておこう。
今回の作戦内容
で、
本題だ。
今回入れたいユーザー
名は
固定データとバッファリングデータのどっちかな。ユーザー
名はとくに
変わることもないのでわざわざリピートして
何回も
共有する
必要はないから、
固定データだね。
視覚化するとこんな
感じにしたい↓
ということで、そろそろコーディングしていこうか。
改修を1つ
本題をコーディングする
前に、一
箇所だけ
改修しておこうと
思う。
ブロック定義を編集する
ブロック
定義「
順番にデコードする」を
編集して、
文字「//」と引数「メモ」を追加してほしい。
ブロック定義の実行するとこにデータ名を追加する
このブロック
定義が
使われている
箇所で、いったいなんのデータをデコードしようとしているのか
書き
込んでおこう。
クラウド変数を受信する
次のプレイヤーデータを移す
クローンティック
ok-scratch
u003cpu003eこの引数はとくに使い道はないんだけど、こうするとu003cemu003e後日見返したときに最高に分かりやすいu003c/emu003eと思わない?u003c/pu003eu003cpu003eちなみにスラッシュを2つ追記したのは、Javascriptなどのプログラミングではメモを書くときにはスラッシュを2つ書いてから書くというルールがあるからなんだ。それをなぞってみた。u003c/pu003e
文字列をエンコードする
いまあるブロック
定義「エンコードする」は、
数値を
取り
扱うことはできても
文字列を
取り
扱うことはできないよね。そのため
文字列をエンコードする
仕組みを、
数字のエンコードとは
別に
作っていく
必要があるんだ。
準備
じゃあ
新しく
文字列をエンコードするために
以下の2つの
重要なコーディングをしていくよ。
- あらかじめエンコードできる文字一覧を保持したリスト
- 文字列をエンコードする専用のブロック定義
リストを作る
文字一覧というリストを
作るよ。このリストはゲーム
開始後に
変更されることはないから、
「変わらない変数」という意味で「定数」と
呼ばれる。でもスクラッチだと
定数という
概念はないから、「これは
定数として
扱う」と
明示するために
接頭語に■を
付けておこう。
初期化する
このリストを
初期化する。このリストには
想定される
英数字をすべて
入れていくんだけど、
95文字あるから1つずつ手作業で入れるのは手間すぎるんだ。だからトリッキーだけど
初期化用のループを1つ
作っておくよ。
リストの中を削除するところから始める
どこか
適当な
場所に
次のブロックを
置いてみて。
緑の
旗が
押されたとき、とかは
不要だよ。クリックして
実行することになるから。
リストの1番目に文字をズラッと入れる
続けて
次の
文字列をリストに
追加しよう。
1文字目は半角の空白だから注意。しっかり
全文字コピーしてね。
!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~
↑をコピペして
次のようにブロックを
置いてね。
ループを置こう
文字数の数だけループさせる
リストの1
番目にズラッと
追加した
文字の
数だけ
繰り
返す
条件式を
作りたいから、
次のブロックを
用意して↓
これをループの
条件式に
当てはめよう。
先頭の文字から順番にリストに追加していく
このループの
中で、
先頭の
文字から
順番に
追加していくよ。
先頭の
文字を
取得する
方法は
次のブロックで
実現できる。
リストには1つだけデータが
入った
状態だよね。だから「リストの
長さ」というブロックからは「1」が
返ってくる。リストの1
番目にはさっきのズラッと
長い
文字列が
入ってて、
最初の
文字は
空白だから、↑このブロックが
返すのは
空白文字になる。これをリストに
追加してみよう。
できあがったブロックを、ループ
内で
実行するように
配置しよう。
これで
リストの長さはどんどん増えるよね。
最初は1だったけど、1つ
追加されたあとは2になるから、
次は2
文字目である「!」が
取得される。それも
追加すれば
長さは3になるから……っていう
感じで
結果的に
全文字追加される
仕組みなんだ。
最後にリストの1番目を消す
ブロック全体をクリックして実行する
この
一連のブロックたちはクリックすれば
実行できる。ためしにクリックしてみて。
結果はこうなるはず↓
95文字すべて入ってればOK!このブロックは
念のため
消さないでどこかに
置いておこう。
ok-scratch
u003cpu003e1文字ずつの定数リストを初期化するときに便利な方法だからバックパックしておいてもいいかも。u003c/pu003eu003cpu003eこの方法じゃなくてもテキストファイルをリストにインポートする方法もあるし、グリフパッチさん達が作ってるスクラッチアドオンを使っている人なら直接リストにデータをコピペしたりも出来る。u003c/pu003e
ブロック定義を作る
名前は「
文字列をエンコードする」だよ。あとは
分かりやすく
引数名や、
実行後に
結果が
格納される
変数名を
書いておくのも
吉!
文字列をエンコードする作戦
さぁ、このブロック
定義の
中身を
作り
込む前に
何をどう
作るのか
作戦を
共有しておきたい。まず
前提として
引数「
文字列」にはユーザー
名が
渡される
予定だ。ここではサンプルとして
僕のユーザー
名である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
文字ずつ
調べた
格納場所を
全部くっつけてエンコード
文字列に
追記する。でこのエンコード
文字列をクラウド
変数に
渡せば
送信は
完了!
ここまでが
今から
作るブロック
定義の
中身だ。よっし、
一緒に
手を
動かしてみよう!
ok-scratch
u003cpu003eちなみに読み取るときは、最初に先頭の10という数字を取得することで、このあとの10文字分のデータがひとかたまりの文字データなんだなと把握できる。そしてまた文字一覧と照らし合わせて、各数字がどの文字なのかを調べるんだ。まぁそれはもうちょい後でやるね。u003c/pu003e
コーディングする
作戦内容をコーディングしていこう!
まず文字列の長さをエンコードしてしまう
まずは
引数で
渡されてくる
文字列の
長さを
調べる。そのためには
実は
新しい処理はいらない。すでにある
ブロック定義「エンコードする」にそのまま文字列の長さを渡してあげればいい。これでエンコード
文字列には、
例えば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文字は二桁」という前提が変わるから、そのあたりも
調整する
必要があるよ。まぁユーザー
名を
共有するだけなら
日本語は
入らないから
問題ない!ますますのオンラインゲーム
制作を
応援しているぜ。