C++はlua:LuaBridgeと結合して、変数と関数を含むすべてをより簡単にします.

8351 ワード

なぜLuaを使うのですか?
C++とスクリプトを組み合わせて使用するのは非常に良い実践であり、この使い方は非常に大きな柔軟性と自由空間を提供します.スクリプト・ファイルは、プロファイルと複雑な関数の作成に使用できます.さらに重要なのは、スクリプトファイルを変更して再コンパイルする必要がなく、集中力と分散を避けることができます.
ソースコードを変更せずに、新しいスクリプトを追加したり、既存のオブジェクトの機能を変更したりする方法を知らないシステムを設計することもできます.もっとLuaがなぜこんなに素晴らしいのか知りたいなら、この文章を読むことができます.『The Beginning of This Article』
前の記事では、ライブラリをバインドする方法を書きましたが、このライブラリの機能は非常に基礎的で、他のライブラリが持つ能力はありません.自分の(C++からLua)バインドを書くのは本当に難しいです.これは非常に多くのテンプレート知識とメタプログラミング知識に関連しているからです.
多くの(C++からLuaへのバインド)ライブラリをテストしたところ、LuaBridgeが最もよく使われていることがわかりました.MITライセンスに基づいており、他に依存するものはなく、C++11も必要ありません.構築する必要はありません.LuaBridgeフォルダをプロジェクトフォルダにドラッグし、ヘッダファイルを含めるだけでいいです.
最小プロジェクト設定
倉庫からLuaBridgeをダウンロードする:倉庫アドレス
同時にLuaをダウンロードします
LuaのincludeディレクトリとLuaBridgeをあなたのプロジェクトのincludeディレクトリに追加し、同時にlua 52を追加します.libはあなたのプロジェクトにリンクします.
新しいscript.luaファイルには、次のコードが書かれています.
testString = "LuaBridge works!"
number = 42

mainを追加します.cppはあなたのプロジェクトにあります.
// main.cpp
#include 
#include 
extern "C" {
# include "lua.h"
# include "lauxlib.h"
# include "lualib.h"
}
 
using namespace luabridge;
int main() {
    lua_State* L = luaL_newstate();
    luaL_dofile(L, "script.lua");
    luaL_openlibs(L);
    lua_pcall(L, 0, 0, 0);
    LuaRef s = getGlobal(L, "testString");
    LuaRef n = getGlobal(L, "number");
    std::string luaString = s.cast<:string>();
    int answer = n.cast();
    std::cout << luaString << std::endl;
    std::cout << "And here's our number:" << answer << std::endl;
}

注意:プログラムのコンパイルに失敗し、エラーが発生した場合は、「error C 2065:『lua_State』:undeclared identifier」in luahelpers.h、次のような修正が必要です.
  • 次のコードセグメントをLuaHelpersに追加する.hの開始部
  • extern "C" {
    # include "lua.h"
    # include "lauxlib.h"
    # include "lualib.h"
    }

        2.Stack.hファイルの460行目のコード
    lua_pushstring (L, str.c_str(), str.size());

    に改心
    lua_pushlstring (L, str.c_str(), str.size());

    はい、またmain.cpp修正下
    #include 
    #include 
    extern "C" {
    # include "lua.h"
    # include "lauxlib.h"
    # include "lualib.h"
    }

    私たちはすべての重要なヘッダファイルを含み、他の例外はありません.
    using namespace luabridge;

    LuaBridgeには独自のネーミングスペースがあります(luabridgeを使用するとネーミングスペースが導入されます)
    lua_State* L = luaL_newstate();

    このコードはLua仮想マシンを新規作成しました
    luaL_dofile(L, "script.lua");

    このコードは私たちのスクリプトを開きました.
    luaスクリプトを開くたびに新しい仮想マシン(lua_State)を開く必要はありません.これは1つだけ使用できます.
    次にluaライブラリをロードしてスクリプトを呼び出します
    luaL_openlibs(L);
    lua_pcall(L, 0, 0, 0);

    次に、LuaRefオブジェクトを作成します.LuaRefは、Luaのすべてのタイプの変数を持つことができます.
    int,float,bool,string,table  。
    LuaRef s = getGlobal(L, "testString");
    LuaRef n = getGlobal(L, "number");
           LuaRef   C++     :
    std::string luaString = s.cast<:string>();
    int answer = n.cast();

    エラーチェック
    時には間違いがあるので、私たちは優雅にこれらの間違いを処理することを学ばなければなりません.最も重要なエラーをチェックしましょう
    スクリプトが見つかりません
    if (luaL_loadfile(L, filename.c_str()) ||
        lua_pcall(L, 0, 0, 0)) {
        ... // script is not loaded
    }

    変数が見つかりません
    変数が空かどうかを確認できます
    if (s.isNil()) {
        std::cout << "Variable not found!" << std::endl;
    }

    変数は私たちが望んでいるタイプではありません
    変数がstringであることを確認したい場合は、このようにすることができます.
    f(s.isString()) {
        luaString = s.cast<:string>();
    }


    テーブルは配列だけでなく、すべてのLuaタイプ、さらにはテーブルを保存できることに驚きました.script.luaには次のコードが書かれています.
    window = {
        title = "Window v.0.1",
        width = 400,
        height = 500
    }

    C++に次のコードを追加
    LuaRef t = getGlobal(L, "window");
    LuaRef title = t["title"];
    LuaRef w = t["width"];
    LuaRef h = t["height"];
    std::string titleString = title.cast<:string>();
    int width = w.cast();
    int height = h.cast();
    std::cout << titleString << std::endl;
    std::cout << "width = " << width << std::endl;
    std::cout << "height = " << height << std::endl;

    次の結果が得られます
     Window v.0.1
     width = 400
     height = 500

    ご覧のように、テーブル要素を取得する方法は[]オペレータを使用することであり、より短く書くこともできます.
    int width = t["width"].cast();

    このようにテーブルの内容を変更することもできます
    t["width"] = 300

    スクリプトは変更されていませんが、この値を再び取得すると、異なる結果が得られます(実際にはC++で設定した結果です):
    int width = t["width"].cast(); // 400
    t["width"] = 300
    width = t["width"].cast(); // 300

    次の表があるとします.
    window = {
        title = "Window v.0.1",
        size = {
            w = 400,
            h = 500
        }
    }

    どうやってwindowを手に入れますか?size.wの値?
    次のようにします.
    LuaRef t = getGlobal(L, "window");
    LuaRef size = t["size"];
    LuaRef w = size["w"];
    int width = w.cast();

    これは私が発見した最も短い書き方で、もし誰かがもっと良い方法を発見したら、私にメールを送ったり、コメントを書いたりしてください.私はとても感謝します.
    私のチュートリアルの第1部に行って、私が実装したコードを見つけることができます.それは、テーブルのデータをより簡単に取得することができます.なぜなら、あなたはこのようにすることができるからです.
    int width = script->get("window.size.w");

    これは作者自身が実現した機能であり、LuaBridgeの機能ではない可能性があります.
    関数#カンスウ#
    C++で簡単な関数を実現
    void printMessage(const std::string& s) {
        std::cout << s << std::endl;
    }

    script.luaには次のコードが書かれています.
    printMessage("You can call C++ functions from Lua!")

    次のように、C++にこの関数を登録する必要があります.
    getGlobalNamespace(L).
       addFunction("printMessage", printMessage);

    注意:luaLを呼び出す必要があります.dofile間で上のコードを呼び出す
    注:C++とLuaは別の名前を持つことができます
     
    printMessage関数を登録したばかりで、基本的なネーミングスペースに登録したい場合は、次のようにします.
    getGlobalNamespace(L).
        beginNamespace("game")
            .addFunction("printMessage", printMessage)
    .endNamespace();

    Luaでこのように呼び出す必要があります
    game.printMessage("You can call C++ functions from Lua!")

    LuaのネーミングスペースはC++のネーミングスペースとは何の関係もなく、管理と便利さの目的で使用されています.
     
    C++でLua関数を呼び出す
    -- script.lua
     
    sumNumbers = function(a,b)
        printMessage("You can still call C++ functions from Lua functions!")
        return a + b
    End
    
    // main.cpp
    LuaRef sumNumbers = getGlobal(L, "sumNumbers");
    int result = sumNumbers(5, 4);
    std::cout << "Result:" << result << std::endl;

    次の出力が表示されます.
    You can still call C++ functions from Lua functions!
    Result:9

    はい、かっこいいですか?LuaBridge関数のパラメータと戻りタイプを教える必要はありません.
    考えなければならないことがあります
    1つの関数に8つ以上のパラメータは使用できません
    8以上のパラメータが渡されると、LuaBridgeはそれを無音に無視します.しかし、エラーが発生すると、LuaBridgeはLuaException異常を放出し、それをキャプチャして処理することを確認します.
    次に、完全な関数の例コードを示します.
    -- script.lua
    printMessage("You can call C++ functions from Lua!")
     
    sumNumbers = function(a,b)
        printMessage("You can still call C++ functions from Lua functions!")
        return a + b
    End
    
    // main.cpp
    #include 
    #include 
    extern "C" {
    # include "lua.h"
    # include "lauxlib.h"
    # include "lualib.h"
    }
     
    using namespace luabridge;
     
    void printMessage(const std::string& s) {
        std::cout << s << std::endl;
    }
     
    int main() {
        lua_State* L = luaL_newstate();
        luaL_openlibs(L);
        getGlobalNamespace(L).addFunction("printMessage", printMessage);
        luaL_dofile(L, "script.lua");
        lua_pcall(L, 0, 0, 0);
        LuaRef sumNumbers = getGlobal(L, "sumNumbers");
        int result = sumNumbers(5, 4);
        std::cout << "Result:" << result << std::endl;
        system("pause");
    }

    次に何をしますか?
    はい、次の章では、クラス、オブジェクトの作成、オブジェクトのライフサイクル......という興味深い内容があります.どうせ多くの内容がそうです.