Blog

[Unreal Engine 4] Lua スクリプトで設計がより柔軟に(4)

執筆者 : K.T

はじめに


UE4 には、ブループリントというビジュアルスクリプティングシステムがあります。

非常に強力な機能ですが、あらゆる局面でブループリントが最適解かと言えば、そうでもありません。

テキストベースのスクリプトという選択肢を加えることで、設計の柔軟性向上が期待できます。

この記事の内容


「パズル」テンプレートに、Lua というテキストベースのスクリプトを組み込みます。

ロジックを Lua で実装し、パッケージ化した後でもロジックを変更できるようにします。

長いので、4回に分けてお送りしています。

第1回はプロジェクトを作成して LuaMachine プラグインを組み込みました。

第2回はデフォルトの Lua スクリプトファイルと、C++ ソースファイルを実装しました。

第3回は UE4 エディタ上で必要な変更を行い、ロジックを Lua で実装したバージョンを完成させました。

第4回(今回)はパッケージ化を行い、実行ファイルを動作させたままで、2種類のゲームを追加します。

使用するもの


 ・Unreal Engine 4.26.2

 ・Visual Studio 2017

 ・LuaMachine 20201211

パッケージ化


メニューから 編集>プロジェクト設定 を選択してください。

パッケージ化>コピーする追加の非アセットディレクトリ に、コンテンツフォルダ以下の NonAssets/Lua を追加します。

パッケージ化>ビルドコンフィギュレーション を Shipping に設定します。

パッケージ化>ステージングディレクトリ は、出力先を設定してください。

メニューから ファイル>プロジェクトをパッケージ化>Windows(64-bit) を選択してください。

出力先を指定すると、パッケージ化が始まります。

無事にパッケージ化できたら、UE4 エディタを閉じてください。

これ以降はパッケージ化ファイルを使用するため、UE4 エディタは使用しません。

パッケージ化ファイルの動作確認


指定した出力先に、WindowsNoEditor フォルダが作成されています。

この中にパッケージ化ファイルが入っているので、開いて確認しましょう。

LuaSample.exe がパッケージ化された実行ファイルです。

LuaSample/Content/NonAssets/Lua 以下には、Lua スクリプトファイルがコピーされています。

WindowsNoEditor 以下の LuaSample.exe を実行してください。

UE4 エディタ上でプレイした時と同様の画面が現れます。

青いブロックをクリックした時や、Restart ボタンを押した時の動作も同じですね。

パッケージ化に成功したことを確認できました。

このプログラムはこのまま使用するので「終了しないで」記事を読み進めてください。

Lua スクリプトファイルの追加(1:順押しゲーム)


もう少しゲームらしくしてみましょう。

LuaSample/Content/NonAssets/Lua 以下に Main_1.lua を追加してください。

また Start.lua を以下のように変更します。

追加できたら、プログラムの Restart ボタンを押してください。

再起動時に Start.lua 経由で Main_1.lua が実行され、ゲームの内容が変化しました。

こちらは数字の書かれたブロックを、1から順にクリックしていくゲームです。

ナンバータッチや、タッチザナンバーズという名前でご存知かもしれません。

全てのブロックをクリックするとクリアとなり、かかった時間が表示されます。

ブロックが9個では、ちょっと簡単すぎますね。

Main_1.lua の先頭2行を、以下のように変更して保存してください。

local   GRID_SIZE = 5

local   GRID_MARGIN = 20.0

保存できたら、プログラムの Restart ボタンを押してください。

ブロックが25個に増えて、だいぶゲームらしくなりました。

【コラム】 C++ プログラマが陥りやすい罠


Lua は C++ プログラマにとって比較的とっつきやすいと言われますが、注意点もあります。

私が特にやりにくさを感じるのは、テーブルのインデクスが 1 ベースである点です。

これは Lua と C++ でインデクスを共用する場合に問題となります。

インデクスが Lua のテーブルを指すのか C++ の配列を指すのか、常に意識しておかないとズレが生じます。

そしてこのズレは時としてかなり発見しにくいバグの原因となります。

ちなみに Lua のインデクスが 1 ベースなのは、Lua の前身である Sol という言語が、非プログラマ向けに設計されたからだそうです。

非プログラマにとっては、1 ベースの方が抵抗感が少ないのかもしれません。

しかしこのために C++ との親和性が若干損なわれているのは、プログラマにとっては残念なところです。

Lua スクリプトファイルの追加(2:消灯ゲーム)


アクションゲームの次は、じっくり考えるパズルゲームを作ってみましょう。

LuaSample/Content/NonAssets/Lua 以下に Main_2.lua を追加してください。

また Start.lua を以下のように変更します。

追加できたら、プログラムの Restart ボタンを押してください。

再起動時に Start.lua 経由で Main_2.lua が実行され、ゲームの内容が変化しました。

こちらは黄色の(点灯している)ブロックをクリックして、灰色に変える(消灯する)ゲームです。

ライツアウトという名前でご存知かもしれません。

クリックしたブロックと一緒に、上下左右のブロックも反転するのがポイントです。

ブロックの反転を繰り返して…

全てのブロックを消灯させたらクリアとなります。

ブロックが16個では、物足りない方もいるかもしれませんね。

Main_2.lua の先頭行を、以下のように変更して保存してください。

local   GRID_SIZE = 8

保存できたら、プログラムの Restart ボタンを押してください。

ブロックが64個に増えて、一気に手強くなりました。

【コラム】 self について


Lua スクリプト中に頻出する self について、補足説明します。

このワードは、Lua 関数の呼び出し元の Lua コンポーネントを指しています。

例えば script_table:initialize() という初期化関数があります。

この関数が C++ 側から呼び出される時は、(暗黙の引数として)self という名前で Lua コンポーネントが渡されます。

self.set_title_text() は、渡された Lua コンポーネント内の Table という連想配列から、set_title_text() を取得して呼び出します。

一方で self を付けずに記述された C++ 側の関数・変数は、Lua ステート内の Table という連想配列から取得されます。

C++ 側のローカルな関数・変数は、Lua コンポーネント内に格納されており、Lua 側では self 付きで記述するC++ 側のグローバルな関数・変数は、Lua ステート内に格納されており、Lua 側では self 無しで記述する

このように考えればわかりやすいかと思います。

複数の Lua コンポーネントを使い分ける例としては、第3回の 【コラム】 LuaMachine の使い方 で紹介したチュートリアルがわかりやすいので、参考になさってください。

まとめ


今回はパッケージ化を行い、実行ファイルを動作させたままで、2種類のゲームを追加しました。

一連の記事はこれで完結ですが、興味を持たれた方はぜひ Lua スクリプトをいじって遊んでみてください。

また Lua スクリプトから呼び出すための関数を C++ 側に追加してみるのも、理解を深める上でお勧めです。

テキストベースのスクリプトが持つ利便性や柔軟性を、少しでもお伝えできたなら幸いです。

参考リンク


Lua 公式

LuaMachine – GitHub

LuaMachine – マーケットプレイス

Why do Lua arrays(tables) start at 1 instead of 0?

Unreal Engine 4関連記事(ORENDA技術ブログ)

著作権表示


Lua

Copyright (c) 1994-2021 Lua.org, PUC-Rio.

Released under the MIT license

LuaMachine

Copyright (c) 2018 Roberto De Ioris

Released under the MIT license