【Unity】uGUIでスクロール可能なテキストボックスを作る

続きも少しだけ書きました。

はいどーもこんばんはニートです。
本日はuGUIを使ってスクロール可能なテキストボックスを作ってみます。

完成サンプルはこんな感じ。

uGUIって使ったことないんだけど、手頃な実習形式の記事ねーかなーみたいな人にピッタリかなと思います。

ちなみに僕はUnity歴一ヶ月未満、C#は文法書を一通り読んだだけの初心者です。
この記事の内容は鵜呑みにしないようご注意ください。
あ、あとuGUIってなんやねんとか、Unityのインストール方法わからへんねんけど……みたいな人は別の記事読んできてください。

また、この記事は『UntyゲームUI実践ガイド』を参考にしています。
より詳しくuGUIについて知りたい方はぜひ購入してみてください。

使用する画像のダウンロード

画像はこちらで用意しておきました。
以下のURLからダウンロードしてください。
https://github.com/Tsumio/unity-sample-maskbox/archive/v1.0.0.zip
ダウンロードが完了したら、Unityで新規プロジェクトを作成し(2Dです)、SpritesフォルダをProjectウィンドウにコピーしてください。
Scriptsフォルダも同様です。

今回の目標

さて下準備が整ったところで、今回の目標を書いておきます。

・uGUIを使ってスクロール可能なテキストボックスを作る
・Mecanimを使ったアニメーションと連携させる

この二つだけです。

大雑把な作業手順は

1.スプライトの設定
2.テキストボックスの作成
3.アニメーションの作成
4.連携させる

こんな感じでしょうか。

わりと丁寧に説明するので、Unityに慣れている人にとっては退屈な記事かもしれません(というか完成サンプルを見た時点で回れ右してほしい)。

ほな始めましょう。

スプライトの設定

まずはウィンドウを9スライスしましょう。
SpritesフォルダのWindowを選択し、インスペクターからSprite Editorを起動します。
設定はこんな感じ。

設定が終了したらApplyを押してください。これで設定が適用されます。

この作業の意味を説明します。
このWindow画像は拡大して使うことを想定しています。
ですがそのまま拡大するとぼやけてしまいますよね。
それではWindow画像としてよろしくないです。
そこで画像を9つにわけ(9スライス)、拡大してもぼやけなくするのです(特定の部位を並べて表示させている)。
設定した20という値を変えれば4隅の大きさも変えられます。
画像に合わせて変更してください。

ひとまずスプライトの設定はこれだけです。

テキストボックスの背景を作る

次はテキストボックスの見た目を作っていきます。
Hierarchyウィンドウを右クリックし、UI→Imageを選択してください。
このUIがいわゆるuGUIと呼ばれている一群のオブジェクトになります。
作成されたImageオブジェクトの名前を「TextBox」に変更後、Source Imageに先ほど作成したウィンドウ画像を(Projectウィンドウから)ドラッグ&ドロップします。
これで画像のイメージが変わります。

次は位置と大きさを変更します。
このウィンドウは画面の一番下に表示させたいので、アンカーを以下のように設定します。

この画像のアンカーは、画面のサイズにかかわらずどこに表示させるか? というものが設定できちゃう代物です。
また、設定によっては「画面の幅だけ画像を広げる」なんてこともできちゃいます。
便利ですねえ。

座標と大きさはこんな感じ。

PosX:0
PosY:100
Width:600
Height:200

Gameビューで確認して以下のような感じで表示されていればOKです。
なんかうまく表示できてないなあと思ったら、アスペクト比を変えてみてください(僕は16:9で作っています)。

テキストを表示させる

お次はテキストを表示させてみましょう。
HierarchyウィンドウでTextBoxを右クリックし、UI→Textを選択します。
名前はMainTextとしておきます。
初期設定だとフォントが小さくて見にくいので、まずサイズを30に変更しちゃいましょう。
この時点で、表示されていた文字が消えますw
どうやらこのTextオブジェクトは、自身の幅や高さを超える文字が設定されると表示しなくなるようです。
これは都合が悪いですね。
とりあえずWidthを550にし、Heightを200あたりにしてみましょう。
「New Text」という文字が表示されましたね。
今回は文字をスクロールさせたいので、少し長めの文字を設定します。
New Textを以下の文字列に置き換えてみましょう。

サンプルテキストです。
おうおうおうおう~。
おいらがボイラ~~~~。いえいえオイラ~それいけオイラ~。
うんこ神拳!
ほああたたたた!
ほあー!ウンコ!
テストテキストですよ。
でんがなまんがな。
ほあちょー!

すると「うんこ神拳!」までしか表示されないことが確認されると思います。
Heightを調整すればよいのですが、手動で調整するのはなんだか面倒ですよね。
というわけで、Add ComponentからContent Size Fitterコンポーネントを追加しましょう。
Vertical FitをPreferred Sizeに変更します。

これで文字量に合わせて自動で高さが設定されます。
実際、最後まで文章が表示されていることが確認できますね。

あとはいい感じの位置にテキストを配置します。

注*Content Size FitterコンポーネントでHeightが変更されても、Y座標はそのままです。
つまり、Heightが変わると(文章の内容が変わると)文章の表示位置がおかしくなります。
今回はひとまずこのまま行きますが、スクリプトを作成して動的にY座標を変更すればこの問題を解決できると思います。
が、Unity標準の機能でもっとうまい方法があるかもしれません。この辺は詳しい人の助言を待たれよ!

マスクを作成する

このままでは表示されたくない場所(ウィンドウの枠の上)にも文章が表示されてしまうので、マスクを作成します。
HierarchyウィンドウのTextBoxを右クリックし、UI→Imageを選択します。
名前をMaskに変更しておきましょう。

さてMaskオブジェクトを作成していきましょう。
まずAdd ComponentからRectMask2Dを追加します。
これはマスク用のコンポーネントです。
次にColorのアルファ値を0に変更します。これで完全な透明になります。
が、これだと編集作業がやりにくいので、マスクの編集中だけちょっと色をつけるのもありです。

Widthを550、Heightを180にし、いい感じの位置にマスクを設置してください(必要があればアンカーも設定してください)。

マスクの作成が完了したら、MainTextをMaskの子オブジェクトにします。
Hierarchyウィンドウがこんな感じになっていたらOKです。

これでマスク内のみテキストが表示されたかなと思います。

スクロールバーの作成

テキストボックスはいよいよ大詰めです。
最後にスクロールバーをつけてみましょう。
例のごとくTextBoxを右クリックし、UI→Scrollbarを選択してください。
横向きのスクロールバーが表示されましたね。
まずはこれを縦向きに変えます。

InspectorウィンドウのDirectionをBottom To Topに変更します。
その後、いい感じの位置にスクロールバーを配置します(必要があればアンカーも設定してください)。

次はスクロールバーのバーとスクロール可能な領域を持つオブジェクトをリンクさせる必要があります。
ここではMaskオブジェクトですね。
HierarchyウィンドウのMaskを選択し、Scroll Rectコンポーネントを追加してください。

追加後、InspectorウィンドウのContentにスクロールさせるオブジェクトを追加します。
ここではMainTextですね。
また、今回は横向きのスクロールは不要ですので、Horizontalのチェックも外しておきます。

この時点でスクロールが可能になるのですが、まだバーとの連携が終わっていません。
MaskオブジェクトのScroll RectコンポーネントにあるVertical ScrollBarに、先ほど作ったScrollbarを追加してください。
これでバーとの連携も完了です。

これでスクロール可能なテキストボックスが完成しました。
実行してみてください。

Mecanimでアニメーションを作る

ここまでで目的はほぼ達成したので、あとはおまけみたいなもんです。
動画みたいな棒人間の動かし方が知りたいなーという人は読んでみてください。

まずは人間を組み立てます。
Hierarchyウィンドウを右クリックし、空のオブジェクトを作成します。名前はHumanとしておきましょう。
その後、そのHumanオブジェクトにImageオブジェクトを4つ追加してください。
名前はBody、Face、ArmLeft,ArmRightとします。
それぞれのSource Imageに、Spritesフォルダから適切な画像をセットします(FaceはAngryをセットしてください)。
このとき、Set Native Sizeボタンを押すとうまい具合にサイズを調整してくれます。
ぜひ活用してみてください。

その後、いい感じに組み立てます。

ついでに腕のPivotを根本あたりに変更します。

あとでアニメーションさせるときにこれが活きてきます。

HierarchyウィンドウでHumanを選択したあと、Window→Animationをクリックします。
Createというボタンが表示されていると思いますので、クリックして「Angry」というファイルを作成します。
Create New Clipから「Smile」というファイルも作成しておきましょう。

Angryの設定はこのままでいいので、Smileアニメーションを作成します。
Add PropertyからFace→Image→Spriteを選択してください。
アニメーションビューに怒っている画像が表示されていると思いますので、これを笑顔の画像に変えます。

これでアニメーション実行時に笑顔になるようになりました。
次は腕を振る動作を付け加えます。
Add PropertyからArmRight→RectTransform→Rotationを追加します。
Rotation.zを変更し、適当に腕を振るアニメーションを作成しましょう。
このとき、赤いボタンをONにしていないとアニメーションの設定が記録されないようです。

左腕も同様に作成しますが、左腕はロケットパンチのように飛ばしたいので、Anchored Positionプロパティも追加し、適当にXの値を変更してロケットパンチのアニメーションを作成してください。

ここまで読んでMecanimについてよくわからないという方は、一度他のサイトでMecanimの基礎を調べてみてください。
かなり複雑ですが、慣れると簡単なアニメーションくらいならササッと作れちゃいます。

Animatorの設定

ゲーム画面上でアニメーションを動かすためにAnimatorの設定をしましょう。
HierarchyウィンドウのHumanオブジェクトを選んだ状態で、Animatorウィンドウを開いてください。
以下のような感じになっているかなと思います。

まずはトリガーを作成しましょう。
Parametersの横にある+ボタンを押し、Triggerを選びます。

Triggerの名前は「AngryTirigger」にしておきましょう。
同様にして「SmileTrigger」も作成します。

次はTransitionの作成です。
画面右側のAngryを右クリックし、Make Transitionを選んでください。
矢印が出るので、Smileに合わせます。
同様にSmileを右クリック・Make Transitionして今度はAngryに繋げます。

先ほど作成した矢印をクリックして、InspectorウィンドウのHas Exit Timeのチェックを外します。
さらにTransition Durationの値を0にしましょう。
そして最後にConditionsのプラスマークをクリックし、AngryからSmileに伸びる矢印にはSmile Triggerを、SmileからAngryに伸びる矢印にはAngry Triggerを設定してください。

最終的にこんな感じになってればOKです。
Has Exit Timeとかに関してはこの記事が詳しいです。

スクリプトを追加する

最後に自作スクリプトを追加しましょう。
HierarchyウィンドウのHumanオブジェクトをクリックし、Add ComponentからHumanManagerを追加してください。
これはUnityに用意されているスクリプトではなく、自作したものとなります(Scriptsフォルダにあります)。

次に、MaskオブジェクトのScroll RectコンポーネントのOn Value Changedのプラスマークをクリックしてください。
None(Object)となっている箇所にHumanオブジェクトを追加します。
さらに、No Functionとなっている箇所を選択し、HumanManager→StartSmileAnimationを選んでください。

これでゲームを実行してみてください。
テキストボックスをスクロールさせるとアニメーションが再生され、スクロールを止めてしばらくするとアニメーションが停止すると思います。
うまく動かない場合、おそらくstring型でオブジェクトを検索している箇所がうまく働いていないのではないかなと思います。
適切な名前に変更してください。
具体的には

・Animator.StringToHash
・GameObject.Find
・HumanAnimator.SetTrigger

あたりでしょうか。

プログラムの内容

https://github.com/Tsumio/unity-sample-maskbox/blob/master/Scripts/HumanManager.cs
コードは手元のものでも、GitHubのものを直接参照してもらっても構いません。
やっていることは単純で、スクロールバーの値が変更されたらStartSmileAimation関数を呼び出し(Scroll RectコンポーネントのOn Value Changedイベント)、StartSmileAimation関数内でアニメーションの設定+CallStartAngryAnimationコルーチンを呼び出すようにしています。
CallStartAngryAnimationコルーチンはStartSmileAimation関数が呼び出されたときのScrollBarのvalueプロパティの値を保持しています。
この保持している値と、一秒後のvalueプロパティの値を比較し、その値が等しければ「スクロールバーは動いていない」と判定します(つまりアニメーションをAngryに戻す)。
もしも値が変化しているなら、アニメーションに変化は加えず、そのまま自分を再帰的に呼び出します。

それほど複雑なことはやっていませんが、このプログラムを参考にするのは推奨しません。
初めにも書きましたが、僕はそもそもC#の知識がほとんどありません(文法書を一通り読んだくらい)。C#のお作法を全く知りません。
また、Unity独自の機能もうまく使いこなせていません(Unityを使い始めて一ヶ月も経っていない)。
なので、このコードは参考程度にして、プログラミングに自信のある方はより適切なプログラムを組んでください。

課題

以上で解説はおしまいです。
ここからは僕の個人的な課題です。

Content Size FitterコンポーネントでHeightが変更されても、Y座標はそのまま
動的に位置を調整するプログラムを書くか、なんやかんやで位置調整する機能をググってみます。
たぶん後者のほうがスマートでしょうが、よくわからなければ前者で実装します。

どうもY座標は変更されるようですが、スクロールバーと連携すると少し意図した箇所と違う変更がされるようです。修正したいですねえ。
・イベントトリガーコンポーネントでスクロールしているかどうかを判断したかったが、やり方がよくわからなかった
自作プログラムでゴリ押し解決した箇所ですね。
あんまりスマートじゃないので、これもそのうち解決策を探したいところです。

特に一つ目の課題は致命的なので、そのうち修正用のスクリプトを作ります。

終わりに

UIの作成という一点だけで言えば、ツクールMVはUnityに勝てる要素が皆無だなあと思いました。
ツクールMVはWindow関連がわりかし便利だと思っていたのですが、それさえもuGUIの前では霞んでしまいますね。
実際にこの講座をやってみた方ならおわかりの通り、プログラムを全く書かなくてもオシャレなUIが作れちゃいます。
これはツクールMVでは考えられないことです。
ツクールMVもUI関連の機能の強化をお願いしますよ……。

が、UIプラグイン等を売る側として考えると、生半可なUIでは見向きもされなさそうなのがUnityは辛そうですね(プログラミング全くできなくてもそれなりのものが簡単に作れるため)。
実際UI関連で売られてるもの見た感じ、やっぱりめちゃくちゃ豪華です。
これくらいのもの作れないとUnity界隈では厳しいんですねえ……。

エディタ改造もやってみたいのですが、uGUIが思いのほか面白かったので、もう少しuGUIの勉強をしてみましょうかねぇ。
ほな、そんな感じで。

続きも少しだけ書きました。

追記:この記事では最初だけアンカーの設定を書いていますが、色々な環境に対応させたいなら全てのオブジェクトにアンカーの設定をした方がよいです。

フォローする