C++ 게임 엔진에서 Lua 스크립팅을 위한 바인딩 기법

C++ 기반 게임 엔진에서 Lua 스크립팅을 활용하는 것은 게임 개발에서 높은 유연성을 제공하는 중요한 기법입니다. Lua는 가벼운 스크립팅 언어로, 성능이 중요한 C++ 엔진과 조화를 이루면서도 개발자가 손쉽게 게임 로직을 수정할 수 있도록 돕습니다.

본 기사에서는 C++과 Lua 간의 바인딩 기법을 다루며, 직접적인 C API 활용법부터 sol2 및 LuaBridge 같은 바인딩 라이브러리를 활용하는 방법까지 폭넓게 설명합니다. 또한 C++ 객체를 Lua에서 다루는 방법과 성능 최적화 전략까지 실무적인 내용을 포함하여 게임 개발자들이 보다 효과적으로 Lua 스크립팅을 도입할 수 있도록 돕습니다.

목차
  1. Lua와 C++의 상호 작용 개요
    1. Lua에서 C++ 함수 호출
    2. C++에서 Lua 스크립트 실행
    3. Lua 스택과 데이터 교환
  2. Lua 스크립팅을 게임 엔진에서 사용하는 이유
    1. 1. 게임 로직의 유연한 수정 가능
    2. 2. 성능과 확장성
    3. 3. AI 및 이벤트 시스템 구현
    4. 4. 다양한 게임 엔진에서 지원
    5. 5. 크로스플랫폼 호환성
    6. 결론
  3. Lua-C++ 바인딩 방법 개요
    1. 1. Lua C API를 이용한 직접 바인딩
    2. 2. sol2 라이브러리를 이용한 바인딩
    3. 3. LuaBridge를 이용한 객체 바인딩
    4. 4. SWIG을 이용한 자동 바인딩
    5. 어떤 바인딩 방법을 선택해야 할까?
    6. 결론
  4. 직접 C API를 활용한 Lua 바인딩
    1. 1. Lua 스크립트 실행
    2. 2. C++ 함수 바인딩 (Lua에서 C++ 함수 호출)
    3. 3. Lua에서 C++ 변수 읽기 및 쓰기
    4. 4. C++에서 Lua 함수 호출
    5. 5. C++ 객체를 Lua에서 사용하기
    6. 결론
  5. sol2를 이용한 C++ Lua 바인딩
    1. 1. sol2 설치 및 기본 설정
    2. 2. Lua 스크립트 실행
    3. 3. C++ 함수를 Lua에서 호출하기
    4. 4. Lua에서 C++ 변수 읽기 및 쓰기
    5. 5. C++에서 Lua 함수 호출
    6. 6. C++ 객체를 Lua에서 사용하기
    7. 7. 성능 비교: sol2 vs. Lua C API
    8. 결론
  6. LuaBridge를 이용한 바인딩 방식
    1. 1. LuaBridge 설치 및 기본 설정
    2. 2. Lua 스크립트 실행
    3. 3. C++ 함수를 Lua에서 호출하기
    4. 4. Lua에서 C++ 변수 읽기 및 쓰기
    5. 5. C++에서 Lua 함수 호출
    6. 6. C++ 객체를 Lua에서 사용하기
    7. 7. 성능 비교: LuaBridge vs. sol2 vs. Lua C API
    8. 결론
  7. 바인딩된 Lua 스크립트에서 C++ 객체 사용
    1. 1. sol2를 사용한 C++ 객체 바인딩
    2. 2. LuaBridge를 사용한 C++ 객체 바인딩
    3. 3. Lua에서 C++ 객체를 리스트로 관리하기
    4. 4. Lua에서 C++의 싱글톤 객체 접근
    5. 5. Lua에서 C++의 콜백 함수 활용
    6. 결론
  8. 성능 최적화 및 바인딩 유지보수
    1. 1. Lua 바인딩에서 성능이 중요한 이유
    2. 2. Lua 바인딩 성능 최적화 방법
    3. 🔹 (1) 데이터 변환 최소화
    4. 🔹 (2) 메타테이블 활용 (Lua 객체 최적화)
    5. 🔹 (3) Lua C API 직접 사용 (최적화된 함수 호출)
    6. 🔹 (4) Lua 가비지 컬렉션 관리 (메모리 최적화)
    7. 3. 유지보수 전략
    8. 4. 성능 비교: sol2 vs. LuaBridge vs. Lua C API
    9. 결론
  9. 요약
    1. 🔹 주요 내용 정리
    2. 🔹 어떤 바인딩 방식을 선택할까?
    3. 🔹 결론

Lua와 C++의 상호 작용 개요


C++과 Lua는 상호 보완적인 역할을 수행할 수 있는 조합입니다. C++은 강력한 성능과 정적 타이핑을 제공하는 반면, Lua는 동적 타이핑과 유연한 실행 환경을 지원하여 게임 로직을 쉽게 수정할 수 있도록 돕습니다.

Lua에서 C++ 함수 호출


Lua는 C++에서 정의된 함수를 호출할 수 있으며, 이를 통해 게임 엔진의 핵심 기능을 Lua에서 스크립팅할 수 있습니다. 예를 들어, 캐릭터 이동, AI 동작, UI 갱신 등의 로직을 Lua에서 관리하면서 C++의 성능을 활용할 수 있습니다.

C++에서 Lua 스크립트 실행


반대로, C++ 코드는 Lua 스크립트를 실행하고 결과를 받을 수도 있습니다. 이를 통해 게임의 특정 동작을 Lua로 스크립팅하여 보다 쉽게 조정할 수 있습니다.

Lua 스택과 데이터 교환


C++과 Lua는 서로 다른 데이터 타입을 사용하므로, 상호 작용을 위해 Lua 스택(Lua Stack)을 활용합니다. C++에서 Lua로 데이터를 전달하거나 Lua에서 반환된 데이터를 받아오기 위해 스택을 조작하는 방식이 기본적인 원리입니다.

#include <lua.hpp>

int main() {
    lua_State* L = luaL_newstate();  // Lua 상태 생성
    luaL_openlibs(L);  // Lua 표준 라이브러리 로드

    luaL_dostring(L, "x = 10");  // Lua 코드 실행
    lua_getglobal(L, "x");  // Lua 변수 x를 스택에 푸시
    int x = lua_tointeger(L, -1);  // C++에서 Lua 변수 가져오기

    printf("Lua 변수 x = %d\n", x);

    lua_close(L);  // Lua 상태 종료
    return 0;
}

위 예제에서는 C++에서 Lua 상태를 생성한 후, Lua에서 정의된 변수를 가져오는 방법을 보여줍니다.

Lua와 C++의 상호 작용을 이해하면, C++ 엔진에서 Lua를 활용하여 게임 개발의 유연성을 높일 수 있습니다.

Lua 스크립팅을 게임 엔진에서 사용하는 이유

Lua는 많은 게임 엔진에서 널리 사용되는 스크립팅 언어로, 빠른 실행 속도, 가벼운 메모리 사용량, 유연한 문법 등의 강점을 가지고 있습니다. 특히, 게임 개발에서는 빠르게 게임 로직을 수정하고, 코드 유지보수를 쉽게 하기 위해 Lua와 같은 스크립팅 언어가 필수적으로 사용됩니다.

1. 게임 로직의 유연한 수정 가능


Lua를 사용하면 C++ 코드 전체를 다시 빌드하지 않고도 게임 로직을 동적으로 수정할 수 있습니다. 이는 개발 속도를 크게 향상시키며, 특히 게임 밸런스 조정이나 AI 튜닝과 같은 반복적인 작업을 효율적으로 수행할 수 있습니다.

예를 들어, Lua에서 몬스터의 속도를 조정하는 코드를 변경하면 즉시 게임 내에서 반영할 수 있습니다.

monster_speed = 5.0  -- Lua에서 몬스터 속도 조정

2. 성능과 확장성


Lua는 C++과 직접 연동할 수 있어, 게임의 주요 엔진 부분은 C++로 최적화하고, 변경이 잦은 로직(예: UI, 이벤트, NPC AI 등)은 Lua로 작성하는 방식이 가능합니다. 이러한 구조는 성능과 확장성을 모두 확보하는 데 유리합니다.

3. AI 및 이벤트 시스템 구현


Lua는 동적 타이핑과 간결한 문법을 지원하여 AI 및 이벤트 시스템 구현에 적합합니다. 예를 들어, 특정 이벤트가 발생했을 때 몬스터가 플레이어를 추적하도록 Lua에서 간단히 정의할 수 있습니다.

function onPlayerSpotted()
    enemy:moveTo(player.position)  -- 플레이어를 추적하는 AI 로직
end

4. 다양한 게임 엔진에서 지원


Lua는 다양한 상용 및 오픈소스 게임 엔진에서 공식적으로 지원됩니다. 대표적인 예로 다음과 같은 엔진들이 Lua를 사용합니다.

게임 엔진Lua 지원 여부
Unity (C# 중심)일부 플러그인 지원
Unreal Engine일부 플러그인 지원
Godot기본 지원 (GDScript와 함께 사용 가능)
CryEngineLua 스크립팅 기본 지원
Source EngineLua 지원 가능
Custom C++ 엔진직접 구현 가능

5. 크로스플랫폼 호환성


Lua는 플랫폼 독립적이며, Windows, macOS, Linux뿐만 아니라 모바일(Android, iOS)과 임베디드 시스템에서도 동작할 수 있어 게임을 크로스플랫폼으로 개발하는 데 유리합니다.

결론


Lua는 가볍고 빠른 스크립팅 언어로, C++ 기반의 게임 엔진과 함께 사용하기 적합합니다. 게임 로직을 동적으로 수정할 수 있고, C++의 성능과 확장성을 유지하면서도 간결한 코드로 복잡한 기능을 쉽게 구현할 수 있기 때문에 많은 게임 개발사에서 Lua를 적극적으로 활용하고 있습니다.

Lua-C++ 바인딩 방법 개요

Lua와 C++을 함께 사용하려면 두 언어 간의 바인딩(Binding)이 필요합니다. 바인딩이란 Lua 스크립트에서 C++ 함수를 호출하거나, C++에서 Lua 함수를 실행할 수 있도록 연결하는 작업을 의미합니다.

C++ 게임 엔진에서 Lua를 활용하는 대표적인 바인딩 방법은 다음과 같습니다.

1. Lua C API를 이용한 직접 바인딩


Lua는 자체적으로 C API를 제공하며, 이를 사용하여 C++ 코드에서 Lua 상태를 생성하고, 데이터를 주고받을 수 있습니다.

  • 장점: 가볍고 직접적인 접근이 가능함.
  • 단점: 코드가 길어질 수 있으며, 관리가 어려움.
#include <lua.hpp>

int add(lua_State* L) {
    int a = lua_tointeger(L, 1);
    int b = lua_tointeger(L, 2);
    lua_pushinteger(L, a + b);
    return 1;
}

int main() {
    lua_State* L = luaL_newstate();
    luaL_openlibs(L);

    lua_register(L, "add", add);
    luaL_dostring(L, "print(add(3, 5))");

    lua_close(L);
    return 0;
}

위 예제에서는 add라는 C++ 함수를 Lua에서 호출할 수 있도록 바인딩했습니다.

2. sol2 라이브러리를 이용한 바인딩


sol2는 C++에서 Lua와의 상호 작용을 쉽게 해주는 라이브러리로, 직관적인 문법과 높은 성능을 제공합니다.

  • 장점: 코드가 간결하고 유지보수가 쉬움.
  • 단점: 추가 라이브러리를 필요로 함.
#include <sol/sol.hpp>

int main() {
    sol::state lua;
    lua.open_libraries(sol::lib::base);

    lua["add"] = [](int a, int b) { return a + b; };
    lua.script("print(add(4, 7))");

    return 0;
}

sol2를 사용하면 매우 직관적으로 C++ 함수를 Lua에서 호출할 수 있습니다.

3. LuaBridge를 이용한 객체 바인딩


LuaBridge는 C++ 클래스와 Lua 간의 바인딩을 쉽게 처리할 수 있는 라이브러리입니다.

  • 장점: C++ 객체를 Lua에서 쉽게 다룰 수 있음.
  • 단점: 일부 기능이 제한적일 수 있음.
#include <LuaBridge/LuaBridge.h>

class Player {
public:
    void sayHello() { printf("Hello from C++!\n"); }
};

int main() {
    lua_State* L = luaL_newstate();
    luaL_openlibs(L);

    luabridge::getGlobalNamespace(L)
        .beginClass<Player>("Player")
        .addConstructor<void(*)()>()
        .addFunction("sayHello", &Player::sayHello)
        .endClass();

    luaL_dostring(L, "p = Player(); p:sayHello()");

    lua_close(L);
    return 0;
}

Lua에서 Player 객체를 생성하고, sayHello() 메서드를 호출할 수 있습니다.

4. SWIG을 이용한 자동 바인딩


SWIG는 다양한 언어 간의 바인딩을 자동 생성하는 툴입니다.

  • 장점: 코드 수정 없이 여러 언어에 적용 가능.
  • 단점: 사용법이 비교적 복잡하고, 특정 기능이 제한될 수 있음.
// example.i (SWIG 인터페이스 파일)
%module example
%{
#include "example.h"
%}

SWIG을 사용하면 자동으로 Lua-C++ 바인딩 코드를 생성할 수 있습니다.

어떤 바인딩 방법을 선택해야 할까?


각 바인딩 방법은 다음과 같은 상황에서 적절합니다.

방법사용 사례
Lua C API직접적인 제어가 필요한 경우
sol2간단하고 직관적인 바인딩이 필요할 때
LuaBridgeC++ 객체를 Lua에서 다룰 때
SWIG자동 바인딩이 필요할 때

결론


Lua와 C++을 연결하는 바인딩 방식은 프로젝트의 요구사항에 따라 다르게 선택될 수 있습니다. 기본적인 C API를 직접 사용하는 방법부터 sol2, LuaBridge, SWIG과 같은 라이브러리를 활용하는 방법까지 다양한 접근법이 존재하며, 각 방식의 장단점을 이해하고 적절한 방법을 선택하는 것이 중요합니다.

직접 C API를 활용한 Lua 바인딩

Lua는 공식적으로 C API를 제공하며, 이를 사용하면 C++에서 Lua 코드를 실행하거나, Lua에서 C++ 함수를 호출할 수 있습니다. C API를 직접 활용하면 불필요한 라이브러리 없이도 바인딩을 구성할 수 있지만, 코드가 다소 복잡해질 수 있습니다.

이번 섹션에서는 Lua C API를 활용하여 Lua와 C++을 직접 연결하는 방법을 다룹니다.


1. Lua 스크립트 실행


C++에서 Lua 코드를 실행하려면 luaL_dostring() 또는 luaL_dofile()을 사용합니다.

#include <lua.hpp>

int main() {
    lua_State* L = luaL_newstate(); // Lua 상태 생성
    luaL_openlibs(L); // Lua 기본 라이브러리 로드

    luaL_dostring(L, "print('Hello from Lua!')"); // Lua 코드 실행

    lua_close(L); // Lua 상태 종료
    return 0;
}

위 코드에서 luaL_dostring()을 사용하여 Lua 코드를 직접 실행했습니다.


2. C++ 함수 바인딩 (Lua에서 C++ 함수 호출)


Lua에서 C++의 함수를 호출하려면 함수를 등록해야 합니다. lua_register() 함수를 사용하여 Lua에서 호출할 수 있도록 C++ 함수를 등록할 수 있습니다.

#include <lua.hpp>
#include <iostream>

// Lua에서 호출할 C++ 함수
int add(lua_State* L) {
    int a = lua_tointeger(L, 1); // 첫 번째 인수
    int b = lua_tointeger(L, 2); // 두 번째 인수
    lua_pushinteger(L, a + b); // 반환값 푸시
    return 1; // 반환값 개수
}

int main() {
    lua_State* L = luaL_newstate();
    luaL_openlibs(L);

    lua_register(L, "add", add); // C++ 함수 바인딩

    luaL_dostring(L, "print(add(10, 20))"); // Lua에서 add 함수 호출

    lua_close(L);
    return 0;
}

실행 결과:

30

Lua에서 add(10, 20)을 호출하면, C++의 add 함수가 실행됩니다.


3. Lua에서 C++ 변수 읽기 및 쓰기


Lua에서 변수를 정의한 후 C++에서 해당 변수를 가져오거나, 반대로 C++에서 변수를 설정할 수도 있습니다.

#include <lua.hpp>
#include <iostream>

int main() {
    lua_State* L = luaL_newstate();
    luaL_openlibs(L);

    // Lua 변수 설정
    luaL_dostring(L, "x = 42");

    // Lua 변수 가져오기
    lua_getglobal(L, "x");
    int x = lua_tointeger(L, -1);
    std::cout << "Lua 변수 x = " << x << std::endl;

    lua_close(L);
    return 0;
}

실행 결과:

Lua 변수 x = 42

C++에서 lua_getglobal(L, "x")를 사용하여 Lua에서 정의된 변수를 가져올 수 있습니다.


4. C++에서 Lua 함수 호출


반대로, C++에서 Lua에서 정의한 함수를 실행할 수도 있습니다.

#include <lua.hpp>
#include <iostream>

int main() {
    lua_State* L = luaL_newstate();
    luaL_openlibs(L);

    // Lua 코드 실행
    luaL_dostring(L, "function multiply(a, b) return a * b end");

    // Lua 함수 호출 준비
    lua_getglobal(L, "multiply");
    lua_pushinteger(L, 4);
    lua_pushinteger(L, 5);

    // Lua 함수 실행 (인수 2개, 반환값 1개)
    lua_pcall(L, 2, 1, 0);

    // 결과 가져오기
    int result = lua_tointeger(L, -1);
    std::cout << "multiply(4, 5) = " << result << std::endl;

    lua_close(L);
    return 0;
}

실행 결과:

multiply(4, 5) = 20

위 코드에서 lua_getglobal(L, "multiply")를 사용하여 Lua에서 정의된 multiply 함수를 가져온 후, lua_pcall()을 사용하여 실행합니다.


5. C++ 객체를 Lua에서 사용하기


Lua에서 C++ 객체를 사용하려면 userdata를 활용합니다.

#include <lua.hpp>
#include <iostream>

class Player {
public:
    int health;
    Player(int h) : health(h) {}
    void takeDamage(int dmg) { health -= dmg; }
};

// Lua에서 사용할 C++ 객체 생성
int createPlayer(lua_State* L) {
    int health = lua_tointeger(L, 1);
    Player** udata = (Player**)lua_newuserdata(L, sizeof(Player*));
    *udata = new Player(health);
    return 1;
}

// 객체의 메서드 바인딩
int playerTakeDamage(lua_State* L) {
    Player** udata = (Player**)lua_touserdata(L, 1);
    int dmg = lua_tointeger(L, 2);
    (*udata)->takeDamage(dmg);
    return 0;
}

int main() {
    lua_State* L = luaL_newstate();
    luaL_openlibs(L);

    lua_register(L, "createPlayer", createPlayer);
    lua_register(L, "playerTakeDamage", playerTakeDamage);

    luaL_dostring(L, R"(
        p = createPlayer(100)
        playerTakeDamage(p, 30)
    )");

    lua_close(L);
    return 0;
}

위 코드에서는 C++ 객체 Player를 Lua에서 생성하고, 객체의 takeDamage() 메서드를 호출할 수 있도록 바인딩하였습니다.


결론


Lua C API를 직접 사용하면 불필요한 외부 라이브러리 없이 Lua와 C++을 연결할 수 있지만, 코드가 길어지고 복잡해질 수 있습니다.

다음과 같은 경우 C API를 사용하는 것이 유리합니다.
✅ 외부 라이브러리 없이 직접 제어가 필요한 경우
✅ 게임 엔진 내부에 Lua를 경량으로 포함하려는 경우
✅ 복잡한 라이브러리 없이 Lua 바인딩을 구현하고 싶은 경우

하지만 코드 유지보수가 어렵다면 sol2, LuaBridge 같은 라이브러리를 활용하는 것이 더 효율적일 수도 있습니다.
다음 섹션에서는 sol2를 활용한 바인딩 방법을 다룹니다.

sol2를 이용한 C++ Lua 바인딩

sol2는 C++과 Lua 간의 바인딩을 간편하게 처리할 수 있도록 설계된 라이브러리로, 강력한 성능과 간결한 문법을 제공합니다. 직접 C API를 사용하는 방식보다 코드가 짧아지고 가독성이 향상되며, 유지보수가 용이해집니다.

본 섹션에서는 sol2를 활용하여 Lua와 C++을 연결하는 다양한 방법을 다룹니다.


1. sol2 설치 및 기본 설정

sol2는 단일 헤더 파일로 제공되며, 간단한 설치 과정으로 사용할 수 있습니다.

📌 설치 방법

  1. sol2 GitHub에서 최신 버전 다운로드
  2. sol.hpp 헤더 파일을 프로젝트에 추가
  3. C++17 이상을 사용해야 함 (-std=c++17 옵션 필요)
  4. Lua 라이브러리 (lua.hpp)가 필요함

2. Lua 스크립트 실행

sol2를 사용하면 간단한 코드로 Lua 스크립트를 실행할 수 있습니다.

#include <sol/sol.hpp>
#include <iostream>

int main() {
    sol::state lua;
    lua.open_libraries(sol::lib::base);

    lua.script("print('Hello from Lua!')");

    return 0;
}

Lua 상태를 생성하고, lua.script()로 Lua 코드를 실행할 수 있습니다.
lua.open_libraries()를 통해 기본 라이브러리(math, string, table 등)를 로드합니다.

실행 결과:

Hello from Lua!

3. C++ 함수를 Lua에서 호출하기

sol2를 사용하면 C++ 함수를 Lua에서 직접 호출할 수 있습니다.

#include <sol/sol.hpp>
#include <iostream>

int add(int a, int b) {
    return a + b;
}

int main() {
    sol::state lua;
    lua.open_libraries(sol::lib::base);

    lua["add"] = &add;  // C++ 함수 바인딩
    lua.script("print(add(5, 10))");

    return 0;
}

lua["add"] = &add;를 사용하여 C++ 함수를 Lua에서 호출할 수 있도록 등록할 수 있습니다.

실행 결과:

15

4. Lua에서 C++ 변수 읽기 및 쓰기

C++ 변수를 Lua에서 정의하고, 이를 C++에서 읽어오는 것도 가능합니다.

#include <sol/sol.hpp>
#include <iostream>

int main() {
    sol::state lua;
    lua.open_libraries(sol::lib::base);

    lua.script("x = 42");  // Lua에서 변수 정의
    int x = lua["x"];  // C++에서 Lua 변수 읽기

    std::cout << "Lua 변수 x = " << x << std::endl;

    return 0;
}

lua["변수명"]을 사용하여 Lua 변수 값을 가져오거나 설정할 수 있습니다.

실행 결과:

Lua 변수 x = 42

5. C++에서 Lua 함수 호출

반대로, Lua에서 정의된 함수를 C++에서 실행할 수도 있습니다.

#include <sol/sol.hpp>
#include <iostream>

int main() {
    sol::state lua;
    lua.open_libraries(sol::lib::base);

    lua.script(R"(
        function multiply(a, b)
            return a * b
        end
    )");

    sol::function multiply = lua["multiply"];
    int result = multiply(4, 7);  // Lua 함수 호출

    std::cout << "multiply(4, 7) = " << result << std::endl;

    return 0;
}

sol::function multiply = lua["multiply"];를 사용하여 Lua 함수를 C++에서 실행할 수 있습니다.

실행 결과:

multiply(4, 7) = 28

6. C++ 객체를 Lua에서 사용하기

sol2를 사용하면 C++ 클래스도 Lua에서 쉽게 활용할 수 있습니다.

#include <sol/sol.hpp>
#include <iostream>

class Player {
public:
    int health;

    Player(int h) : health(h) {}

    void takeDamage(int dmg) {
        health -= dmg;
    }
};

int main() {
    sol::state lua;
    lua.open_libraries(sol::lib::base);

    lua.new_usertype<Player>("Player",
        sol::constructors<Player(int)>(),
        "health", &Player::health,
        "takeDamage", &Player::takeDamage
    );

    lua.script(R"(
        p = Player(100)
        print("Initial health: " .. p.health)
        p:takeDamage(30)
        print("After damage: " .. p.health)
    )");

    return 0;
}

lua.new_usertype<Player>()를 사용하여 C++ 클래스를 Lua에서 사용 가능하도록 바인딩할 수 있습니다.

실행 결과:

Initial health: 100
After damage: 70

7. 성능 비교: sol2 vs. Lua C API

비교 항목Lua C APIsol2
코드 가독성낮음 (코드 복잡)높음 (간결)
유지보수어려움쉬움
바인딩 속도빠름약간 느림
추가 라이브러리 필요 여부없음필요 (sol2)
C++ 객체 사용어렵고 복잡쉬움

sol2는 C API보다 코드가 훨씬 간결하고 유지보수가 쉬운 장점이 있지만, 추가 라이브러리가 필요하며 성능 최적화가 필요한 경우에는 직접 C API를 사용하는 것이 유리할 수도 있습니다.


결론

sol2는 C++과 Lua를 연결하는 가장 강력하고 직관적인 바인딩 라이브러리 중 하나입니다.
🔹 코드 가독성이 뛰어나고 유지보수가 용이
🔹 C++ 클래스 바인딩을 쉽게 처리 가능
🔹 Lua와 C++ 간의 함수 및 변수 공유가 편리함

그러나 추가 라이브러리 사용이 부담되거나, 성능이 극도로 중요한 경우에는 Lua C API를 직접 사용하는 것이 더 적절할 수도 있습니다.

다음 섹션에서는 LuaBridge를 활용한 바인딩 방법을 다룹니다.

LuaBridge를 이용한 바인딩 방식

LuaBridge는 경량 C++ 라이브러리로, C++ 클래스 및 객체를 쉽게 Lua와 바인딩할 수 있도록 설계되었습니다. Lua C API보다 간결하고, sol2보다 가벼운 바인딩을 제공하며, 성능과 코드 가독성을 동시에 유지할 수 있는 장점이 있습니다.

본 섹션에서는 LuaBridge를 활용하여 C++과 Lua를 연결하는 방법을 다룹니다.


1. LuaBridge 설치 및 기본 설정

LuaBridge는 단일 헤더 파일 기반의 라이브러리로, Boost나 추가적인 빌드 설정이 필요하지 않습니다.

📌 설치 방법

  1. LuaBridge GitHub에서 최신 버전 다운로드
  2. LuaBridge/LuaBridge.h 헤더 파일을 프로젝트에 추가
  3. Lua 라이브러리(lua.hpp)가 필요함

💡 C++11 이상을 사용하는 것이 권장됩니다.


2. Lua 스크립트 실행

LuaBridge는 Lua 상태를 생성하고 Lua 코드를 실행하는 과정을 간단하게 처리할 수 있습니다.

#include <lua.hpp>
#include <LuaBridge/LuaBridge.h>
#include <iostream>

int main() {
    lua_State* L = luaL_newstate();  // Lua 상태 생성
    luaL_openlibs(L);  // Lua 표준 라이브러리 로드

    luaL_dostring(L, "print('Hello from Lua!')");  // Lua 코드 실행

    lua_close(L);
    return 0;
}

luaL_dostring()을 사용하여 Lua 코드를 실행할 수 있습니다.

실행 결과:

Hello from Lua!

3. C++ 함수를 Lua에서 호출하기

LuaBridge를 사용하면 C++ 함수를 Lua에서 바로 호출할 수 있도록 바인딩할 수 있습니다.

#include <lua.hpp>
#include <LuaBridge/LuaBridge.h>
#include <iostream>

int add(int a, int b) {
    return a + b;
}

int main() {
    lua_State* L = luaL_newstate();
    luaL_openlibs(L);

    // C++ 함수를 Lua에서 사용할 수 있도록 등록
    luabridge::getGlobalNamespace(L)
        .addFunction("add", &add);

    luaL_dostring(L, "print(add(5, 10))");  // Lua에서 add 함수 호출

    lua_close(L);
    return 0;
}

luabridge::getGlobalNamespace(L).addFunction("add", &add);를 사용하여 C++ 함수를 Lua에서 호출할 수 있도록 등록할 수 있습니다.

실행 결과:

15

4. Lua에서 C++ 변수 읽기 및 쓰기

LuaBridge는 변수 공유도 쉽게 처리할 수 있습니다.

#include <lua.hpp>
#include <LuaBridge/LuaBridge.h>
#include <iostream>

int main() {
    lua_State* L = luaL_newstate();
    luaL_openlibs(L);

    // Lua에서 변수 정의
    luaL_dostring(L, "x = 42");

    // C++에서 Lua 변수 읽기
    luabridge::LuaRef x = luabridge::getGlobal(L, "x");
    std::cout << "Lua 변수 x = " << x.cast<int>() << std::endl;

    lua_close(L);
    return 0;
}

luabridge::getGlobal(L, "변수명")을 사용하여 Lua 변수를 C++에서 읽을 수 있습니다.

실행 결과:

Lua 변수 x = 42

5. C++에서 Lua 함수 호출

C++에서 Lua에서 정의된 함수를 호출하는 것도 가능합니다.

#include <lua.hpp>
#include <LuaBridge/LuaBridge.h>
#include <iostream>

int main() {
    lua_State* L = luaL_newstate();
    luaL_openlibs(L);

    luaL_dostring(L, R"(
        function multiply(a, b)
            return a * b
        end
    )");

    // Lua 함수 호출
    luabridge::LuaRef multiply = luabridge::getGlobal(L, "multiply");
    int result = multiply(4, 7);

    std::cout << "multiply(4, 7) = " << result << std::endl;

    lua_close(L);
    return 0;
}

luabridge::LuaRef multiply = luabridge::getGlobal(L, "multiply");를 사용하여 Lua 함수를 C++에서 실행할 수 있습니다.

실행 결과:

multiply(4, 7) = 28

6. C++ 객체를 Lua에서 사용하기

LuaBridge는 C++ 클래스를 Lua에서 직접 사용할 수 있도록 바인딩하는 기능을 제공합니다.

#include <lua.hpp>
#include <LuaBridge/LuaBridge.h>
#include <iostream>

class Player {
public:
    int health;

    Player(int h) : health(h) {}

    void takeDamage(int dmg) {
        health -= dmg;
    }
};

int main() {
    lua_State* L = luaL_newstate();
    luaL_openlibs(L);

    // C++ 클래스를 Lua에서 사용 가능하도록 등록
    luabridge::getGlobalNamespace(L)
        .beginClass<Player>("Player")
        .addConstructor<void(*)(int)>()
        .addProperty("health", &Player::health)
        .addFunction("takeDamage", &Player::takeDamage)
        .endClass();

    luaL_dostring(L, R"(
        p = Player(100)
        print("Initial health: " .. p.health)
        p:takeDamage(30)
        print("After damage: " .. p.health)
    )");

    lua_close(L);
    return 0;
}

beginClass<Player>()를 사용하여 C++ 클래스를 Lua에서 사용 가능하도록 바인딩할 수 있습니다.

실행 결과:

Initial health: 100
After damage: 70

7. 성능 비교: LuaBridge vs. sol2 vs. Lua C API

비교 항목Lua C APIsol2LuaBridge
코드 가독성낮음 (코드 복잡)높음 (간결)중간
유지보수어려움쉬움쉬움
바인딩 속도빠름약간 느림빠름
추가 라이브러리 필요 여부없음필요 (sol2)필요 (LuaBridge)
C++ 객체 사용어렵고 복잡매우 쉬움쉬움
런타임 오버헤드낮음약간 있음낮음

LuaBridge는 C API보다 쉽게 사용할 수 있으며, sol2보다 가벼운 대안으로 적절한 선택이 될 수 있습니다.
✅ 그러나 sol2는 더 강력한 기능과 문법적인 유연성을 제공합니다.


결론

LuaBridge는 sol2보다 가볍고 C API보다 사용하기 쉬운 바인딩 라이브러리로,
💡 C++ 클래스 및 객체를 Lua에서 쉽게 다룰 수 있도록 지원합니다.
💡 추가적인 빌드 설정 없이 헤더 파일만으로 쉽게 사용할 수 있음
💡 C++과 Lua 간의 데이터 교환 및 함수 호출이 간편

다음 섹션에서는 Lua 스크립트에서 C++ 객체를 활용하는 방법을 다룹니다.

바인딩된 Lua 스크립트에서 C++ 객체 사용

C++ 게임 엔진에서 Lua 스크립트를 사용할 때 가장 중요한 기능 중 하나는 Lua에서 C++ 객체를 직접 다루는 것입니다. 이를 통해 게임 캐릭터, 몬스터, 아이템 등의 객체를 Lua에서 조작할 수 있으며, 엔진의 핵심 로직을 수정하지 않고도 게임 로직을 변경할 수 있습니다.

이번 섹션에서는 sol2와 LuaBridge를 사용하여 Lua에서 C++ 객체를 활용하는 방법을 다룹니다.


1. sol2를 사용한 C++ 객체 바인딩

sol2는 C++ 클래스를 Lua에서 다룰 수 있도록 자동으로 바인딩할 수 있습니다.

#include <sol/sol.hpp>
#include <iostream>

class Player {
public:
    int health;

    Player(int h) : health(h) {}

    void takeDamage(int dmg) {
        health -= dmg;
    }
};

int main() {
    sol::state lua;
    lua.open_libraries(sol::lib::base);

    // C++ 클래스를 Lua에서 사용할 수 있도록 바인딩
    lua.new_usertype<Player>("Player",
        sol::constructors<Player(int)>(),
        "health", &Player::health,
        "takeDamage", &Player::takeDamage
    );

    lua.script(R"(
        p = Player(100)  -- C++ 객체 생성
        print("Initial health: " .. p.health)
        p:takeDamage(30)
        print("After damage: " .. p.health)
    )");

    return 0;
}

lua.new_usertype<Player>()를 사용하여 C++ 클래스를 Lua에서 사용 가능하도록 바인딩할 수 있습니다.
✅ Lua에서 Player 객체를 생성하고, C++의 takeDamage() 메서드를 호출할 수 있습니다.

실행 결과:

Initial health: 100
After damage: 70

2. LuaBridge를 사용한 C++ 객체 바인딩

LuaBridge도 유사한 방식으로 C++ 객체를 Lua에서 다룰 수 있도록 지원합니다.

#include <lua.hpp>
#include <LuaBridge/LuaBridge.h>
#include <iostream>

class Player {
public:
    int health;

    Player(int h) : health(h) {}

    void takeDamage(int dmg) {
        health -= dmg;
    }
};

int main() {
    lua_State* L = luaL_newstate();
    luaL_openlibs(L);

    // C++ 클래스를 Lua에서 사용할 수 있도록 등록
    luabridge::getGlobalNamespace(L)
        .beginClass<Player>("Player")
        .addConstructor<void(*)(int)>()
        .addProperty("health", &Player::health)
        .addFunction("takeDamage", &Player::takeDamage)
        .endClass();

    luaL_dostring(L, R"(
        p = Player(100)  -- C++ 객체 생성
        print("Initial health: " .. p.health)
        p:takeDamage(30)
        print("After damage: " .. p.health)
    )");

    lua_close(L);
    return 0;
}

beginClass<Player>()를 사용하여 C++ 클래스를 Lua에서 생성하고 사용할 수 있도록 바인딩합니다.
✅ sol2와 유사한 방식으로 C++ 객체를 Lua에서 호출할 수 있습니다.

실행 결과:

Initial health: 100
After damage: 70

3. Lua에서 C++ 객체를 리스트로 관리하기

Lua에서 여러 개의 C++ 객체를 리스트로 저장하고 활용할 수도 있습니다.

#include <sol/sol.hpp>
#include <iostream>
#include <vector>

class Enemy {
public:
    int health;

    Enemy(int h) : health(h) {}

    void takeDamage(int dmg) {
        health -= dmg;
    }
};

int main() {
    sol::state lua;
    lua.open_libraries(sol::lib::base);

    lua.new_usertype<Enemy>("Enemy",
        sol::constructors<Enemy(int)>(),
        "health", &Enemy::health,
        "takeDamage", &Enemy::takeDamage
    );

    lua.script(R"(
        enemies = {}
        for i = 1, 3 do
            enemies[i] = Enemy(100)  -- 여러 객체 생성
        end

        for i, e in ipairs(enemies) do
            e:takeDamage(i * 10)  -- 각 객체에 피해 적용
            print("Enemy " .. i .. " health: " .. e.health)
        end
    )");

    return 0;
}

Lua에서 C++ 객체 배열을 관리할 수 있으며, 이를 통해 다수의 게임 캐릭터, 몬스터 등의 개체를 쉽게 조작할 수 있습니다.

실행 결과:

Enemy 1 health: 90
Enemy 2 health: 80
Enemy 3 health: 70

4. Lua에서 C++의 싱글톤 객체 접근

게임 엔진에서는 전역적인 싱글톤(Singleton) 객체를 Lua에서 호출해야 할 수도 있습니다.

#include <sol/sol.hpp>
#include <iostream>

class GameManager {
public:
    static GameManager& getInstance() {
        static GameManager instance;
        return instance;
    }

    void printMessage() {
        std::cout << "GameManager is working!" << std::endl;
    }
};

int main() {
    sol::state lua;
    lua.open_libraries(sol::lib::base);

    lua["GameManager"] = &GameManager::getInstance();
    lua.set_function("printMessage", &GameManager::printMessage, GameManager::getInstance());

    lua.script(R"(
        GameManager:printMessage()
    )");

    return 0;
}

싱글톤 객체를 Lua에서 직접 접근할 수 있도록 등록할 수 있습니다.

실행 결과:

GameManager is working!

5. Lua에서 C++의 콜백 함수 활용

게임 엔진에서는 이벤트 시스템을 구현할 때 Lua에서 콜백을 등록하고, C++에서 호출하는 구조가 필요할 수도 있습니다.

#include <sol/sol.hpp>
#include <iostream>

sol::function luaCallback;

void triggerEvent(int value) {
    if (luaCallback.valid()) {
        luaCallback(value);
    }
}

int main() {
    sol::state lua;
    lua.open_libraries(sol::lib::base);

    lua.set_function("registerCallback", [](sol::function func) {
        luaCallback = func;
    });

    lua.script(R"(
        registerCallback(function(x)
            print("Event triggered with value: " .. x)
        end)
    )");

    triggerEvent(42);  // C++에서 Lua 함수 호출

    return 0;
}

✅ Lua에서 등록한 콜백을 C++에서 이벤트가 발생했을 때 실행할 수 있습니다.

실행 결과:

Event triggered with value: 42

결론

Lua에서 C++ 객체를 다루는 것은 게임 개발에서 매우 중요한 기능이며, 이를 활용하면 게임 엔진을 보다 유연하게 설계할 수 있습니다.

sol2와 LuaBridge를 사용하면 C++ 객체를 Lua에서 쉽게 바인딩하고 조작 가능
Lua에서 C++ 객체를 배열로 관리하고, 싱글톤 객체 및 콜백 함수도 활용 가능
성능이 중요한 경우, sol2보다 LuaBridge가 가벼운 선택지가 될 수 있음

다음 섹션에서는 Lua 바인딩의 성능 최적화 및 유지보수 전략을 다룹니다.

성능 최적화 및 바인딩 유지보수

C++과 Lua를 바인딩할 때, 올바르게 최적화하지 않으면 성능 저하나 메모리 누수 등의 문제가 발생할 수 있습니다.
본 섹션에서는 Lua 바인딩 성능을 최적화하는 방법과 유지보수 전략을 다룹니다.


1. Lua 바인딩에서 성능이 중요한 이유

게임 엔진에서 Lua 바인딩은 다음과 같은 이유로 성능에 영향을 줄 수 있습니다.

C++과 Lua 간의 데이터 변환 비용: 변수를 주고받을 때, 내부적으로 타입 변환이 일어남
Lua 함수 호출 비용: C++에서 Lua 함수를 호출할 때, 호출 스택을 관리하는 비용이 발생
GC(가비지 컬렉션) 비용: Lua에서 객체를 생성하면, GC가 자동으로 관리하지만, 과도한 객체 생성은 성능 저하를 유발

따라서 불필요한 연산을 줄이고, 적절한 바인딩 방식을 선택하는 것이 중요합니다.


2. Lua 바인딩 성능 최적화 방법

🔹 (1) 데이터 변환 최소화

Lua와 C++ 간 데이터 변환이 많아질수록 성능이 저하됩니다.
가능하면 큰 데이터를 한 번에 주고받고, 반복 호출을 줄이는 것이 중요합니다.

// 비효율적인 방식 (반복적인 호출)
lua.script(R"(
    for i = 1, 10000 do
        process(i)  -- C++ 함수 호출
    end
)");
// 최적화된 방식 (배열 전달)
lua.script(R"(
    data = {}
    for i = 1, 10000 do
        data[i] = i
    end
    processBatch(data)  -- C++에서 한 번만 호출
)");

배열을 한 번에 전달하여 호출 횟수를 줄임


🔹 (2) 메타테이블 활용 (Lua 객체 최적화)

C++ 객체를 Lua에서 사용하면 매번 객체를 생성하는 비용이 발생할 수 있습니다.
메타테이블을 활용하면, 불필요한 객체 생성을 방지하고, 메모리 효율성을 높일 수 있습니다.

#include <sol/sol.hpp>

class Enemy {
public:
    int health;
    Enemy(int h) : health(h) {}

    void takeDamage(int dmg) {
        health -= dmg;
    }
};

int main() {
    sol::state lua;
    lua.open_libraries(sol::lib::base);

    lua.new_usertype<Enemy>("Enemy",
        sol::constructors<Enemy(int)>(),
        "health", &Enemy::health,
        "takeDamage", &Enemy::takeDamage
    );

    // 성능 최적화를 위한 메타테이블 적용
    lua.script(R"(
        meta = {}  -- 공유 메타테이블
        function createEnemy(hp)
            local e = Enemy(hp)
            setmetatable(e, { __index = meta })
            return e
        end
    )");

    return 0;
}

메타테이블을 활용하면 메모리 사용량을 줄이고 성능을 향상시킬 수 있습니다.


🔹 (3) Lua C API 직접 사용 (최적화된 함수 호출)

sol2나 LuaBridge는 간편하지만, 직접 Lua C API를 사용하면 불필요한 오버헤드를 줄일 수 있습니다.

#include <lua.hpp>

int fastFunction(lua_State* L) {
    int x = lua_tointeger(L, 1);
    lua_pushinteger(L, x * 2);  // 연산 후 반환
    return 1;
}

int main() {
    lua_State* L = luaL_newstate();
    luaL_openlibs(L);

    lua_register(L, "fastFunction", fastFunction);
    luaL_dostring(L, "print(fastFunction(10))");

    lua_close(L);
    return 0;
}

Lua C API를 직접 활용하면 성능을 더욱 최적화할 수 있음


🔹 (4) Lua 가비지 컬렉션 관리 (메모리 최적화)

Lua의 GC(가비지 컬렉션)는 자동으로 메모리를 관리하지만, 과도한 객체 생성은 성능 저하를 초래할 수 있습니다.

-- GC 강제 실행 (최적화)
collectgarbage("collect")
// C++에서 Lua의 GC 수동 조정
lua_gc(L, LUA_GCCOLLECT, 0);

필요할 때만 GC를 실행하여 성능을 최적화


3. 유지보수 전략

바인딩 라이브러리를 일관되게 사용 (sol2 / LuaBridge 중 하나를 선택)
C++과 Lua 간의 데이터 변환 최소화 (배열을 한 번에 전달)
코드를 모듈화하여 유지보수성 향상 (Lua에서 C++ 모듈을 로드)
C++에서 Lua API 직접 호출 시 메모리 관리에 유의


4. 성능 비교: sol2 vs. LuaBridge vs. Lua C API

비교 항목Lua C APIsol2LuaBridge
성능✅ 빠름⚠️ 중간✅ 빠름
유지보수❌ 어려움✅ 쉬움✅ 쉬움
코드 가독성❌ 복잡함✅ 간결✅ 간결
메모리 효율✅ 좋음⚠️ 추가 오버헤드✅ 좋음
바인딩 속도✅ 빠름⚠️ 약간 느림✅ 빠름

최고의 성능을 원하면 Lua C API를 직접 사용
유지보수성과 개발 속도를 고려하면 sol2 / LuaBridge가 유용
메모리 사용량이 중요한 경우 LuaBridge가 더 나은 선택일 수 있음


결론

C++과 Lua 바인딩을 최적화하면 게임 엔진 성능을 극대화할 수 있습니다.
💡 반복적인 함수 호출을 줄이고, 데이터를 한 번에 전달
💡 메타테이블을 활용하여 객체 재사용
💡 불필요한 GC 실행을 줄여 메모리 사용 최적화
💡 sol2 / LuaBridge / Lua C API 중 프로젝트에 맞는 방식을 선택

다음 섹션에서는 Lua와 C++ 바인딩 기법을 종합적으로 정리합니다.

요약

본 기사에서는 C++ 게임 엔진에서 Lua 스크립팅을 활용하는 방법과 바인딩 기법을 다루었습니다.
Lua는 유연한 게임 로직 관리와 빠른 개발 속도를 제공하는 스크립팅 언어로, C++과의 바인딩을 통해 강력한 성능과 확장성을 확보할 수 있습니다.

🔹 주요 내용 정리

Lua와 C++의 상호 작용: Lua는 C++에서 호출할 수 있으며, C++에서도 Lua 코드를 실행할 수 있음
바인딩 기법 비교:

  • Lua C API: 가장 성능이 뛰어나지만 코드가 복잡
  • sol2: 쉽고 강력한 바인딩 지원, 유지보수성 우수
  • LuaBridge: 가볍고 빠르며, 객체 바인딩에 최적화
    C++ 객체를 Lua에서 사용: 캐릭터, 몬스터 등의 게임 객체를 Lua에서 관리 가능
    성능 최적화: 반복적인 호출 최소화, 메타테이블 활용, GC 최적화

🔹 어떤 바인딩 방식을 선택할까?

기준Lua C APIsol2LuaBridge
성능 최적화✅ 매우 좋음⚠️ 중간✅ 좋음
사용 편의성❌ 복잡함✅ 매우 쉬움✅ 쉬움
C++ 객체 바인딩❌ 직접 구현 필요✅ 자동 처리✅ 지원
메모리 효율✅ 최적화 가능⚠️ 추가 오버헤드✅ 최적화 가능

프로젝트 요구사항에 따라 적절한 방법을 선택하는 것이 중요합니다.

  • 최고의 성능을 원하면 Lua C API
  • 개발 속도와 유지보수성이 중요하면 sol2
  • 메모리 효율과 객체 관리 최적화가 필요하면 LuaBridge

🔹 결론

Lua 바인딩을 활용하면 게임 엔진의 확장성과 유지보수성이 크게 향상됩니다.
C++ 기반의 게임 엔진에서 Lua를 적절히 활용하면 빠르게 게임 로직을 조정하고, AI, UI, 이벤트 시스템을 효과적으로 구현할 수 있습니다.

이제 프로젝트에 맞는 바인딩 방식을 선택하여 C++과 Lua의 강력한 조합을 활용해 보세요! 🚀

목차
  1. Lua와 C++의 상호 작용 개요
    1. Lua에서 C++ 함수 호출
    2. C++에서 Lua 스크립트 실행
    3. Lua 스택과 데이터 교환
  2. Lua 스크립팅을 게임 엔진에서 사용하는 이유
    1. 1. 게임 로직의 유연한 수정 가능
    2. 2. 성능과 확장성
    3. 3. AI 및 이벤트 시스템 구현
    4. 4. 다양한 게임 엔진에서 지원
    5. 5. 크로스플랫폼 호환성
    6. 결론
  3. Lua-C++ 바인딩 방법 개요
    1. 1. Lua C API를 이용한 직접 바인딩
    2. 2. sol2 라이브러리를 이용한 바인딩
    3. 3. LuaBridge를 이용한 객체 바인딩
    4. 4. SWIG을 이용한 자동 바인딩
    5. 어떤 바인딩 방법을 선택해야 할까?
    6. 결론
  4. 직접 C API를 활용한 Lua 바인딩
    1. 1. Lua 스크립트 실행
    2. 2. C++ 함수 바인딩 (Lua에서 C++ 함수 호출)
    3. 3. Lua에서 C++ 변수 읽기 및 쓰기
    4. 4. C++에서 Lua 함수 호출
    5. 5. C++ 객체를 Lua에서 사용하기
    6. 결론
  5. sol2를 이용한 C++ Lua 바인딩
    1. 1. sol2 설치 및 기본 설정
    2. 2. Lua 스크립트 실행
    3. 3. C++ 함수를 Lua에서 호출하기
    4. 4. Lua에서 C++ 변수 읽기 및 쓰기
    5. 5. C++에서 Lua 함수 호출
    6. 6. C++ 객체를 Lua에서 사용하기
    7. 7. 성능 비교: sol2 vs. Lua C API
    8. 결론
  6. LuaBridge를 이용한 바인딩 방식
    1. 1. LuaBridge 설치 및 기본 설정
    2. 2. Lua 스크립트 실행
    3. 3. C++ 함수를 Lua에서 호출하기
    4. 4. Lua에서 C++ 변수 읽기 및 쓰기
    5. 5. C++에서 Lua 함수 호출
    6. 6. C++ 객체를 Lua에서 사용하기
    7. 7. 성능 비교: LuaBridge vs. sol2 vs. Lua C API
    8. 결론
  7. 바인딩된 Lua 스크립트에서 C++ 객체 사용
    1. 1. sol2를 사용한 C++ 객체 바인딩
    2. 2. LuaBridge를 사용한 C++ 객체 바인딩
    3. 3. Lua에서 C++ 객체를 리스트로 관리하기
    4. 4. Lua에서 C++의 싱글톤 객체 접근
    5. 5. Lua에서 C++의 콜백 함수 활용
    6. 결론
  8. 성능 최적화 및 바인딩 유지보수
    1. 1. Lua 바인딩에서 성능이 중요한 이유
    2. 2. Lua 바인딩 성능 최적화 방법
    3. 🔹 (1) 데이터 변환 최소화
    4. 🔹 (2) 메타테이블 활용 (Lua 객체 최적화)
    5. 🔹 (3) Lua C API 직접 사용 (최적화된 함수 호출)
    6. 🔹 (4) Lua 가비지 컬렉션 관리 (메모리 최적화)
    7. 3. 유지보수 전략
    8. 4. 성능 비교: sol2 vs. LuaBridge vs. Lua C API
    9. 결론
  9. 요약
    1. 🔹 주요 내용 정리
    2. 🔹 어떤 바인딩 방식을 선택할까?
    3. 🔹 결론