The Loomの話 その2

第2回目の解説。

まず最初にレベル作成から。

今回のゲームはループもので1つの部屋を使いまわす形になります。

なので部屋を1つ作成すればOK。

いつも通りにBrushで部屋の構造を作成、そこからメッシュを作成しました。

部屋の構成はこんな感じです。

ue196.jpg

天井は非表示にしています。

右奥の部屋がエンディング部屋ですね。エンディング部屋はデフォルトでは壁が非表示ですが、表示しておくと扉から部屋に入った時に壁にぶつかってしまうためです。

ちなみに、この部屋はカットシーンでしか利用されないため、コリジョンはありません。

また、点光源がいくつか置いてありますが、これはエディタで作業中に暗いと困るから、という理由で置いてあります。

Persistent Levelは常に読み込まれているレベルなので、どのレベルでも共通して利用されるものはここで配置しています。

具体的には壁、床、天井、4枚の扉、通路にあるシーリングライトとスポットライトです。

実は奥の通路はゲームクリア時以外は使用されていないため、扉の色も違っていますしメッセージも置いてあります。

予定では奥の扉を開けると自動的に扉の外に出て、カットシーン終了時に最初の通路に飛ばしてループさせようとしました。

が、通路の寸法を微妙に間違えてしまったっぽくてワープさせると部屋が変わってるのがバレバレになってしまいました。

なので諦めてホワイトフェードを入れるようにしました。ホワイトフェードはポストプロセスで作成しています。

Persistent Levelに置かれていない配置オブジェクトはすべてStream Levelとして配置しています。

GameLevelXX.umapという名前で作成し、先に進むと自動的に次のレベルを読み込むようにBPで設定しています。

ue197.jpg

ゲーム内容的にあるゲームレベルは前回のゲームレベルから少しずつ変化させる形になります。

なので基本的には前回レベルの.umapをエクスプローラでコピー、ファイル名変更、既存のレベルを読み込みで追加、という流れで作成しました。

ただしこれだけだとどのオブジェクトがどのレベルに属しているのかわかりにくくなります。なんといってもアクター名が同一になってしまっていますから。

そこでGameLevel00.umapに登録されているアクターをすべてLevel00というフォルダに格納します。

次にGameLevel00.umapをコピーしたGameLevel01.umapを作成し、読み込みます。

この段階でLevel00フォルダに2重にアクターが格納されている状態になりますが、レベルウィンドウでGameLevel00を非表示にするとアウトライナーでもGameLevel00に配置されているアクターが非表示になります。

この状態でLevel00フォルダ内のすべての表示アクターを選択、Level01フォルダに格納します。

Level01フォルダはLevel00フォルダ直下になってしまうので、[Move To Root]でルートに置きます。

これからLevel01を編集し、同じ要領で02,03と作っていきます。

他に試したことですが、ライトマップの焼き付けを試してみました。

ライトマップを焼き付けるためには専用のUVが必要になります。通常はUV Channel 1を利用することになるでしょう。

普通にメッシュを作成するとUVは0番のみになりますが、1番をUniqueUVとして生成する機能がUE4には存在します。

StaticMeshウィンドウを開き、メニューから[Window]->[Generate Unique UVs]を選択するとUV生成ウィンドウが表示されます。

生成するチャンネルをUV1にして適当なパラメータで[Apply]ボタンを押すと生成されます。

UV Channel 1を表示すれば以下のようにUVを確認できます。

ue201.jpg

微妙に斜めってるのがわかると思いますが、これがどうもライトマップには良くないようで、かなり高い解像度でライトマップを生成しても微妙に色々な場所が汚くなってしまいました。

通路だけでもライトマップを適用したかったんですが、結局あきらめました。

自動生成後に手で直すなりした方がいいかもしれませんね。

というわけでレベル作成はここまで。

続きはメッセージ表示とその関係の話です。

特定のオブジェクトを見続けたり特定の場所に移動したりすると画面下にメッセージが表示されます。

メッセージは複数行表示され、一定時間で消えます。

メッセージの表示や表示時間の計測はMyHUDで行っています。

まず、Stringの配列を用意し、ここに複数行のメッセージを入れられるようにします。

メッセージ設定命令は表示時間も含めて設定を行い、表示時間はTickイベントで減少させています。表示時間が0になったらString配列を空にします。

単純な命令なのでこの部分のBPグラフは提示しません。

メッセージ表示位置はGetTextSize命令で1行ごとに高さを計算、すべての行の高さを加算して表示開始のY座標を計算します。

X座標は各行ごとに真ん中に表示されるように、やはりGetTextSize命令から座標を計算しています。

実際にそれほど難しい処理は行っていませんが、一応グラフを提示しておきます。

ue198.jpg

ではここにメッセージを登録するのは誰か、ということですが、これは2つのBPで行っています。

1つは特定場所に移動した際、というかボリュームにプレイヤーが接触した際にメッセージを登録するBP_OverlapMessageTriggerで、もう1つは注視し続けた際にメッセージを登録するBP_AimTriggerBaseです。

前者はそのまま利用しますが、後者はボリュームを持っていないため、継承したBPでボリュームを設定して利用します。

どちらもMessagesというString配列を持っていて、アクターを配置した後にそこにメッセージを登録しています。

ue199.jpg

メッセージを表示する際に必要になるのは当然フォントです。

日本語フォントをほぼすべて作成しておく方法もあるのですが、フォントサイズなどを考慮するとテクスチャ枚数が多くなりすぎてしまいます。

そこでゲーム製作ではよく使われる、使用する文字のフォントだけを作成する手段をとりました。

ゲームで使用するメッセージはたいてい別ファイルで管理するものです。

よくExcelが使われますが、今回は普通にテキストファイルで管理しました。

UE4ではCSVが利用できるのですが、イマイチ使い方がわからなかったので今回はパス。

テキストファイルはUTF-8で保存しておきます。SJISはNG。理由はSJISだとUE4が正常認識してくれないからです。

フォントアセットを作成したら[Import Options]->[Chars File Path]にテキストファイルの格納パスを設定します。

このパスはいろいろ試したのですが、相対パスではうまくいかなかったです。仕方ないので絶対パスで。

また、[Chars File Wildcard]に*.txtを登録します。

あとはテキストを更新したら再インポートするだけですが、DistanceFieldを有効にしているためインポートにはかなり時間がかかります。

通常はDistanceFieldを切っておくか、インポートは暇な時に行うなどしておくべきでしょう。

さて、BP_AimTriggerBaseが持っているメッセージをHUDに登録するのはこのBP自身ですが、その命令を発行しているのはMyCharacterです。

前回にも書きましたが、MyCharacterは毎フレーム、直線のコリジョン判定をとっています。

注視状態でこのBPを注視している状態が1秒間続くと、SetMessageToHUD命令を発行します。

この部分も難しいことはしてないのですが、グラフは提示しておきます。

ue200.jpg

メッセージ関係は以上です。

今回は短めですが、ここまで。

意外と解説する部分も少ないので、たぶん次回で終了です。