スクラッチに挑戦している皆さん、どうも!スクラッチコーチです。
- ① 文字のヨコ幅を自動計算する
- ② 改行しよう、そうしよう (いまここ)
今回のゴール
Scratchで「会話ボックス」を実装し、文字がアニメーションで流れるように表示され、さらに日本語でも自然に改行できる仕組みを作ること。
- スプライト「ふきだし」を使って話者ごとのセリフを表示できる
- セリフをリストで管理し、メッセージや変数を用いて順番に出力できる
- 一文字ずつ描画してアニメーション風に見せられる
- 半角スペースや改行処理を正しく扱える
- 英語だけでなく、日本語でも美しく表示できる
スプライト「ふきだし」を確認する
会話のダイアログボックスにはスプライト「ふきだし」を使うよ。

漫画とかだとセリフが書かれている白い枠のエリアがふきだしだけど、今回は四角くて話者の画像付きのコスチュームを用意してある。キャットとナノがコスチュームにあるから見てみてね。自由に変えていいよ。

会話を追加する定義
スターター作品をリミックスした人は、すでに会話を追加する定義が実装されていると思う。もしリミックスせずに作っている人がいたら、以下のブロックを組んでおいてね。

それにしても左上右下という謎の引数が気になるね。定義を見てみると、リストの中身は以下のようになっているね。
- 1番目は話者の名前
- 2番目はx1(左)。これは見えない会話ボックスの左上のX座標のこと
- 3番目はy1(上)。これは左上のY座標のこと
- 4番目はx2(右)。これは右下のX座標のこと
- 5番目はy2(下)。これは右下のY座標のこと
- 6番目は空白。ここまでが1カタマリのデータですよという宣言なので重要


なんて分かりやすい図なんだ!(ラフですいませんm(_ _)m)
スプライト「キャット」を作る
キャットを開こう。

リスト「★セリフ」を作る
全てのスプライト用ってことがパッと見で分かるように接頭語として★を付けておくと便利。


接頭語で変数やブロック定義などの種類をパッと見で分かるようにする方法は、コーディング規約としてまとめてあるよ。興味がある人はチェックしてね。
変数「★話者の番号」を作る

ここで初期化しておこう。キャットは1にしておくよ。

メッセージ「セリフを最初から最後まで出力する」を作る
ちと長い名前ですがグリフパッチさんの動画に忠実にしてみた。

さっきの話者の番号の初期化に続けて、以下のようにブロックを組んでおいてね。(スクショだと、さっきの変数の初期化が抜けてる)

変数の初期化が消えてたから正しいスクショを掲載しましたm(_ _)m

スプライト「文言」を作る
これは私が作ったオンラインバトルロワイヤルゲーム「IPPON」で使った文言スプライトを使ってる。だから漢字が中途半端。

-
コスチュームに文字を追加すれば自由に拡張できます。フォントを合わせたい場合は「PixelMplus12」というフォントを使っているのでウェブで探してみてください。
メッセージを受け取る
さっき作ったメッセージを受け取って、そのたびにクローンを削除するようにしたい。普通であれば「クローンを削除する」ブロックは終端のブロックなので接続ができないため、メッセージを受け取ったときブロックを2つ用意していたと思う。
しかし、我々はもっとスマートに行こうではないか!
「もし〜ではないなら」という」条件ブロック(常にTRUEなので必ず実行される)を用意して、その中で「このクローンを削除する」ブロックを使えば、実質これでも次ブロックに接続ができるのだ。これが発想の転換、コロンブスの玉子ってやつ。

見た目に関する処理を続けて実装しよう。


明るさを100にすることで文字が白くなる。今回は背景が暗いからこれでいい。もしキミの背景が白いなら、逆に明るさを下げればOK!
定義「ページをリセットする」を作る
再描画せずに実行するよ。


すいません、いつもなら再描画無しで実行する定義って分かるように「_ページをリセットする」って書きます。今回のチュートリアルでは忘れてます……m(_ _)m 第三回からはちゃんと付けておくようにしますので、みんなも再描画なしの定義はアンダーバーを先頭につけておくと分かりやすいと思います〜。
ここで使っておく。

具体的な処理
ページをリセットするという定義だけど、具体的な処理は「カーソルを初期位置に戻す」みたいなイメージ。

実行して文字を一時的に表示されるようにすると、いい感じの場所に1文字目が表示されると思う。


もしズレている人は、会話ボックスの位置を直すか、さっきスプライト「キャット」で定義した会話の追加処理で各引数を調整しよう。
変数「段落」を作る
1つのセリフ、という意味で段落という変数を作っておくよ。

とりあえずセリフの1番目を入れておこう。

定義「一段落ずつ処理する」を作る
再描画アリで一段落ずつ表示する定義を作るよ。

段落の初期化に続けて置いておく。

変数「何文字目か」を作る
一段落ずつ処理する過程で一文字ずつヨコ幅とか計算が必要なので、今は何文字目を処理しているのかを保持しておく変数を作る。

定義「段落から次の文字を取得する」を作る
こっちは再描画ナシで実行する定義だよ。

1段落ずつ処理する過程で、1文字ずつ計算する処理を作っていくよ。

変数「文字」を作る
なんか似たような定義とか変数が増えてきて大混乱の予感(^_^;)
今度は「文字」を作る。


本当は動画だとこれは「word」だから単語、っていう解釈もできる。でも後々に日本語対応するとき、単語よりも文字のほうがしっくり来るので「文字」にした。とはいえ、別になんでもいいので、あとで変えてもOKだよ。
変数「文字」に、変数「段落(=1セリフ)」の1番目の文字を持たせ、そのあとは2番目、3番目の文字を持たせるループを作ろう。

「ずっと」ループだから終わりを明確にしないとバグるよね。そこで文字が空白だったらループを止めるようにする。
そのあとでリスト「文字」に変数「文字」を入れる……いやいや分かりづらいw これは完全にミスった……まぁこのまま突き進む。猪突猛進!
ループの終了条件を作る

ここからの処理はグリフパッチさんの動画では「英語の文法」を前提にプログラムが作られているので、日本語だと不具合がでる。具体的には英語って単語と単語の間に半角スペースが絶対にあるから、半角スペースに依存したプログラミングになっています。とりあえずそのとおりに作ります。この記事の最後で日本語対応するので、いったんグリフパッチさんの動画どおりに作っていきましょう!
もし文字が半角スペースだったら、もうセリフに文字が残ってないということになるので、ループを止めよう。(下のスクショは半角スペースが入ってます。空ではないので注意)


順番に注意!「(半角スペース)に(文字)が含まれる」であって、「(文字)に(半角スペース)が含まれる」ではないよ。これはスクラッチ固有の文法なんだけど、「(文字)に(半角スペース)が含まれる」ってやると絶対にTRUEになってしまうから使えない。ちなみに「(半角スペース)=(文字)」ってやると……どうなるだろう?
定義「文字を出力する」を作る
今度はまた再描画アリの定義を作る。

文字数の数だけ繰り返す処理を作っていく。

最初に作ったデバッグ用のコードが残っていたら、まるっとループの中に入れよう。ない人は改めて組んでほしい。

こんな感じ。

そして固定のコスチュームではなくて、リスト「文字」の中身を割り当てていく。コスチュームにリストの1番目を割り当てたら、リストの1番目を消してしまうことで、常に新しい文字が選択される。こうすればインデックス(何番目かを示す変数)を作らなくてもいいので、時には便利。

やっぱし名前変えます(緊急リファクタリング)
変数「文字」をリスト「文字」に……って分かりづらい!!分かりづらさはプログラミングにおいて敵です。可読性が低いソースコード、みたいな評価になる。なので名前変えて改善しておきます。(こういう改善をリファクタリングとかって言う。まぁ今回みたいに名前変えるだけならリネームのほうが適切かも)

それでも分かりづらいねんw まぁ悩み過ぎも良くない。リストは文だ。変数「文字」を複数持ったリスト「文」なら、まぁさっきよりはマシだよね。
リファクタ後

実行元はこんなかんじ
この定義を呼ぶのはここだよ。

プレビューしてみる
おお、なんか後ろのほうがゴチャゴチャっとなっているけど、文字出た!

ためしに半角スペースを空けてみる
スプライト「キャット」を選んでね。

セリフにわざと半角スペースを入れよう。日本語ではこんな「分かち書き」みたいな書き方は普段しないけど、英語前提で作られているプログラミングに合わせて半角スペースを空けてみる。

すると……

おお!半角スペースでちゃんと文が止まっているね。これは日本語文法だとピンとこないけど、意図した通りのプログラミングではあるので、OK。
定数を作ろう「■空白」「■半角スペース」
空白と半角スペースが分かりづらすぎる……よね。
ステージを選んでね。



緑の旗が押されたらステージで定数を作っておく。定数は、作品のプレイ中には絶対に変えない値、っていうマイルールだよ。

閑話休題
ではコーディングの続きに戻ろう!

まず半角スペースで止まってしまう処理を「ずっと」ループにネストする(入れる)ことで、すべてのセリフが出力されるようにする。

そして全てのセリフが終わったら、ちゃんと終了するように条件を作っておく。じゃないと無限ループになる。定数を活用していく。


リスト「文」にも一文字も残ってないし、変数「文字」も空だよ、っていう状態なら終了と判断するって意味
ついでにさっき半角スペースを直書きしてあった場所にも定数「■半角スペース」を入れておこう。

そして、これも英語用の処理なんだけど、ループの最後でカーソルの位置をヨコにずらす。

プレビューしてみる
これで実行すると……

うん、しっかりスペースが反映されているね。英語なら「How are you?」みたいにスペースで区切られて表示されるようになる。
改行処理を作る
さて、いよいよ本題(おそw)
会話ボックスの右端(冒頭でx2って紹介したところ)に文字が差し掛かったら、カーソルを折り返してx1に戻したい。(もちろんyも)

定義「段落から次の文字を取得する」
そのために、変数「ヨコ幅」を使って今度は単語全体の長さを調べる。勘の良い人ならアレってなるかもしれない。これはまたしても英語の文法が前提になった考え方だからだ。まぁ大丈夫。このとおり作っていこう。

定義「一段落ずつ処理する」
改行する条件分岐はここにいれていく。

条件式はこのとおり。
( X座標 + ヨコ幅 ) > 会話ボックスの右端
コーディングすると以下のようになる。

定義「改行する」を作る
再描画アリで実行する改行処理を作る。

条件ブロック内に入れよう。

Xは左端に戻して、Yは下げる処理
具体的な処理はさっき作った「ページをリセットする」(カーソルを右上に戻す)に似てる。けどちょっと違う。Y座標の位置をタテにずらすように組んであるよ。

改行されるかテストしてみる
やったー!改行された!もちろん課題も見て取れるけど改行には成功している。着実に進んでいるよ!

ちなみにうまく出力されてない文字があるよね。これはコスチュームにないから……具体的には「分」と「作」という漢字がコスチュームにないから直前のコスチュームが繰り返されてる。今回の本質とは関係ないからスルーしていく。とはいえ、次回までには追加しておこうかなぁ……(追加した)
半角スペースを入れてみる
また英語文法に合わせて、なんちゃって分かち書きにしてみる。

半角スペースを適当にいれる。

分かち書きでテストする
OK!改行はばっちり美しいアニメーションになっている。理想的な会話ボックスに近づいたよね。半角スペース空ければいいや、っていう人はこれでもOK!日本語対応したい人は続きもやってみよう(すぐできる)
日本語対応を特別追加
さて、グリフパッチさんの動画は英語文法を前提にしたプログラミングだから、半角スペースを途中に入れることが一般的ではない日本語ではうまく動かない。そこで今回は日本語でも美しくアニメーションされる会話ボックスにする処理を紹介する。このチュートリアルではこちらを採用していくけど、みんなはグリフパッチさんに合わせてもOKだよ。
定義「段落から次の文字を取得する」を修正する
「ずっと」ループを外そう。これで「スペース区切りの1単語(helloとか)のヨコ幅」ではなく1文字ずつ(「は」「ろ」「ー」)のヨコ幅を計算できる。

そして半角スペースは半角スペースとして機能するように、X座標をずらす位置を変えて条件ブロックに入れる。定義「文字を出力する」の直前で実行することに意味があるよ。

日本語化のテスト
実行してみよう!

おおおおお!ちゃんと文字単位で改行が成功しているぞ!これで日本語でも安心して使っていけそうだね。
まとめ(締め)
ここまでで、Scratchで会話ボックスをつくる仕組みを学びました。
- ふきだしスプライトを使ってセリフを表示できる
- リストや変数を活用して、一文字ずつアニメーション表示できる
- 改行や半角スペースを扱う工夫で、英語にも日本語にも対応できる
- 名前付けやリファクタリングを通して、コードの分かりやすさも大切にできた
今回のポイントは、「英語前提の処理をそのまま使うのではなく、日本語に合うように工夫したこと」。これで日本語の会話も自然にアニメーションできるようになりました。
この仕組みを使えば、RPGやアドベンチャーゲーム風の演出もどんどん作れます。
次回は次のセリフもちゃんと出るようにしていきたいって考えてますので、応援よろしくお願いしますっ(๑•̀ㅂ•́)و✧
- ① 文字のヨコ幅を自動計算する
- ② 改行しよう、そうしよう (いまここ)

アスクラッチで質問する