![](https://habrastorage.org/getpro/habr/post_images/118/7a6/2f5/1187a62f58d421298c017ba67ad5fe83.png)
約束どおり、ゲームの作成プロセスで遭遇する技術的な詳細を引き続きお知らせします。
今回は、ゲーム内スクリプトを作成するための言語について話しましょう。
この記事では、自分で作った自転車ではなく、なぜLuaであるかを説明します。 一般的に、ゲームにスクリプト言語が必要な場合があります。 このケースをUnityにねじ込むときの微妙な点と、UniLua統合を使用してこれを行う方法を例として示します。
インターネットの最新情報では、ほとんどゼロであり、このゼロの半分は中国語であるとすぐに言わなければなりません。 だから、あなたは言うことができます-排他的にしてください。
なぜスクリプトが必要なのですか?
このゲームでは、スクリプト化されたさまざまなシーンを表示する必要があります。
クエストの典型的な例を挙げます。 キャラクターは店に入り、強盗があることがわかります。 おびえた売り手の寺院でコウモリを保持している盗賊を示す写真が示されています。 次に、ある種のダイアログが表示されます。 次に、キャラクターが混乱に近づき、アクションを選択するためのウィンドウが表示されます。これは、売り手を支援し、暴走者に配布するか、適合させるためです。
明らかに、ここでは、スプライトを移動し、それらのアニメーションを変更し、プレイヤーに異なるダイアログと画像を表示する必要があります...ここには多くのオプションはありません-各クエストをハードコードするか、このことをスクリプト化してみてください。
明らかに、そのようなことをハードコーディングすることはまったく難しくありません。
なぜルア?
実際、最初は自分の自転車とLuaの間で選択肢がありました。
最初のアプローチから、言語はそれほど必要なく、独自の言語を書くことができるようです。 チームを順番に呼び出して、それで終わりです。 しかし、もう少し深く考えると...スクリプトイベントはゲームのパラメーターに関連するでしょうか? たとえば、以前に殺されたNPCはシーンに表示されません。 またはそのような何か。 そして、これはすでにいくつかの条件、トリガーなどを意味します。
その結果、「単純な言語」のパーサーは非常に複雑な仕掛けをもたらす可能性があり、論理式などのヒープを解析する必要があります。 など
考え直すことなく、他の誰かを使用することが決定され、証明されました。 ルア。 おそらく他の言語もあります...しかし、私が他のゲームで常に見ているのはLuaです。 同じWorld of Warcraftで、MODはこの奇妙な言語で作成され、インデックス作成は1から始まります。
だから、再び-他の人によって検証されたソリューションを使用することが決定されました。
Unityでの統合
これが最初の楽しみの始まりです。 UnityでLuaを実装する最初のライブラリーは、見栄えがよくなります。 しかし、さらに掘り下げてみると、特定の.Netメソッドが使用されていることがわかります。たとえば、携帯電話(および場合によっては他のプラットフォーム)では使用できません。
そして、(万が一に備えて)どこでもサポートされ、できればソースで完全にサポートされ、閉じられたDLLではないライブラリが必要です。
インターネットで調べてみると、中国のプログラマー、 UniLuaが無料で作成されています。 完全な並べ替えとどこでも動作します。
ドックが非常に貧弱で、部分的に中国語で書かれていることを除いて、誰にとっても良いことです。
まあ、ソースがあります! そして脳... =)ダウンロードし、UniLuaフォルダーをプラグインにドロップして(毎回再コンパイルしないように)行ってください。
CからLuaスクリプトを呼び出す#
ここではすべてが比較的簡単です。
using UniLua; private ILuaState _lua; // Lua private ThreadStatus _status; // ... _lua = LuaAPI.NewState(); // string lua_script = ""; // Lua _status = _lua.L_LoadString(lua_script); // if (_status != ThreadStatus.LUA_OK) { Debug.LogError("Error parsing lua code"); } _status.Call(0, 0); // Lua-
実行してみてください。 誰も呪われていなければ、すべてがうまくいきます。 空のスクリプトが成功しました。
LuaからC#関数を呼び出す
次に、このスクリプトの少なくとも一部を操作する方法を学習する必要があります。 明らかに、LuaからC#コードを呼び出す方法を学ぶ必要があります。
パラメーターをログに書き込むだけのメソッドを作成しましょう。
private int L_Trace(ILuaState s) { Debug.Log("Lua trace: " + s.L_CheckString(1)); // return 1; // }
ご覧のとおり、
ILuaState
クラスを使用し
ILuaState
。 これは、すべての入力パラメーターが格納される場所です(Luaから転送したいので、結果を返す必要があります。注意してください!Luaの結果は、
return
ではなく
s.PushInteger()
、
s.PushString()
などで
s.PushString()
。
関数が書かれています。 次に、Luaに接続する必要があります。
private int OpenLib(ILuaState lua) { var define = new NameFuncPair[] // , ( Lua -> C#) { new NameFuncPair("trace", L_Trace), }; lua.L_NewLib(define); return 1; }
次に、_luaオブジェクトを作成した後、このライブラリ記述への接続を追加する必要があります。
_lua.L_OpenLibs(); _lua.L_RequireF("mylib", OpenLib, true);
できた! これで次のことができます。
string lua_script = @" local lib = require ""mylib"" lib.trace(""Test output"") ";
それはすべてのようですか? しかし、違います。 今最も難しい部分。
収量
少し考えれば、Luaスクリプトを継続的に実行すべきではないことを理解できます。 明らかに、一時停止、何らかのアニメーションの終了を待つ、キーを押すなどがあります。 つまり、スクリプトはコントロールをシャープに戻し、その後、ある時点で続行する必要があります。
ここで多くのコピーを壊しました。 これを行う方法の説明は、見つけるのが非常に困難でした(そして、それは別のライブラリのためでした)。
最初に必要なことは、呼び出しではなく、別のスレッドを介してスクリプトを実行することです。
//_status.Call(0, 0); . : _thread = _lua.NewThread(); _status = _thread.L_LoadString(lua_script); _thread.Resume(null, 0);
ここで、C#で、「アニメーションが終了するのを待つ」(
L_WaitForAnimationStop
)
L_WaitForAnimationStop
、これをLuaから呼び出すと想像してください。 ここでの実装は異なる場合がありますので、一般的な原則を説明します。
この関数では、このアニメーションの最後に何らかのコールバックを掛ける必要があり、最も重要なのは、
return 1
を
return 1
代わりにこれを行う必要があることです。
private int L_WaitForAnimationStop(ILuaState s) { // callback' .. _temp_state = s; // ILuaState return s.YieldK(s.GetTop(), 0, null); // Lua, }
そして、コールバックで直接、停止した場所からスクリプトを実行し続ける必要があります
if (_temp_state.GetTop() > 0) _thread.Resume(null, 0);
以上です。 次のようなスクリプト:
lib.trace("starting") lib.wait_for_animation_stop() lib.trace("stopped")
lib.wait_for_animation_stop()
必要な場合にのみ一時停止して続行します(つまり、上記の場合、
Resume()
を実行するコールバックを呼び出します)。
達成されたこと
上記の方法と、 OOPをシミュレートするシャーマニズムを使用して、次の構文を実現することができました。
local ch1 = CharacterGfx() ch1.create("char_0") local ch2 = CharacterGfx() ch2.create("char_1") ch1.moveto("workout") ch2.moveto("fridge") ch2.wait_move_finish() ch1.wait_move_finish() vh.trace("finished ok")
このスクリプトは、2つのキャラクタースプライトを作成し、1つ目を「ワークアウト」ポイントに移動し、2つ目を「冷蔵庫」ポイントに移動します。
ドキュメントから、私はLua 5.2リファレンスマニュアルにのみアドバイスできます。ここでは、これらのすべてのシャーマニズムが説明されていますが、別の実装については少しです。
シリーズのすべての記事: