ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • lua behavior tree
    카테고리 없음 2025. 3. 24. 16:35

    Lua에서 트리를 더욱 직관적으로 표현할 수 있도록 트리 구조 문법을 개선했어!
    이제 트리 생성이 JSON 스타일처럼 간결하고 가독성 좋게 보일 거야! 🚀


    📌 Lua 트리 코드 (트리 문법 지원 추가)

    -- behavior_tree.lua
    
    BehaviorTree = {}
    
    -- 기본 노드 구조
    BehaviorTree.Node = {}
    BehaviorTree.Node.__index = BehaviorTree.Node
    
    function BehaviorTree.Node:new(type, name)
        return setmetatable({type = type, name = name, children = {}}, self)
    end
    
    function BehaviorTree.Node:addChildren(children)
        for _, child in ipairs(children) do
            table.insert(self.children, child)
        end
        return self  -- 체이닝(Chaining) 지원
    end
    
    function BehaviorTree.Node:toString(indent)
        indent = indent or 0
        local prefix = string.rep("  ", indent) -- 들여쓰기
        local result = prefix .. "- [" .. self.type .. "] " .. self.name .. "\n"
    
        for _, child in ipairs(self.children) do
            result = result .. child:toString(indent + 1)
        end
    
        return result
    end
    
    -- Selector 노드
    BehaviorTree.Selector = setmetatable({}, {__index = BehaviorTree.Node})
    function BehaviorTree.Selector:new(name)
        local obj = BehaviorTree.Node:new("Selector", name)
        setmetatable(obj, {__index = self})
        return obj
    end
    
    -- Sequence 노드
    BehaviorTree.Sequence = setmetatable({}, {__index = BehaviorTree.Node})
    function BehaviorTree.Sequence:new(name)
        local obj = BehaviorTree.Node:new("Sequence", name)
        setmetatable(obj, {__index = self})
        return obj
    end
    
    -- Action 노드
    BehaviorTree.Action = setmetatable({}, {__index = BehaviorTree.Node})
    function BehaviorTree.Action:new(name, func)
        local obj = BehaviorTree.Node:new("Action", name)
        obj.func = func or function() return "SUCCESS" end
        setmetatable(obj, {__index = self})
        return obj
    end
    
    function BehaviorTree.Action:run()
        return self.func()
    end
    
    -- 트리의 루트 노드 생성
    BehaviorTree.root = BehaviorTree.Selector:new("Root")
    
    -- 트리 출력 함수 추가
    function BehaviorTree.printTree()
        print(BehaviorTree.root:toString())
    end
    
    return BehaviorTree
    

    이제 Lua에서 트리 구조를 설계하고, C++에서 행동을 구현 및 실행하는 구조로 나눠서 코드를 작성할게! 🚀
    이 방식으로 Lua는 Behavior Tree 설계에 집중하고, C++은 게임 로직을 실행하는 역할을 수행할 수 있어.


    📌 코드 구조

    Lua: 트리 생성 & 설계 (Sequence, Selector, Action 노드)
    C++: 행동(Action) 실행 로직 구현 (Lua에서 호출할 수 있도록 제공)
    C++과 LuaJIT 연동을 통해 Behavior Tree 실행


    📌 1. Lua 코드 (트리 구조 정의)

    -- behavior_tree.lua
    local bt = require("behavior_tree")
    
    -- 트리 정의 (각 행동은 C++에서 처리)
    bt.root:addChildren {
        bt.Sequence:new("Combat") :addChildren {
            bt.Action:new("Attack"),
            bt.Action:new("Defend")
        },
        bt.Selector:new("Idle") :addChildren {
            bt.Action:new("Patrol"),
            bt.Action:new("LookAround")
        }
    }
    
    -- 행동 실행 (C++에서 함수 호출)
    function executeAction(actionName)
        local cppFunction = _G[actionName] -- C++에서 제공하는 함수 실행
        if cppFunction then
            return cppFunction()
        else
            return "FAILURE"
        end
    end
    
    -- 트리 실행 (C++에서 호출)
    function runTree()
        return bt.root:run()
    end
    
    -- 트리 출력
    bt.printTree()
    

    📌 2. C++ 코드 (행동 실행 구현)

    #include <iostream>
    #include <lua.hpp>
    
    // C++에서 제공하는 행동(Action) 함수
    int lua_Attack(lua_State* L) {
        std::cout << "Executing Attack!" << std::endl;
        lua_pushstring(L, "SUCCESS"); // 결과 반환
        return 1;
    }
    
    int lua_Defend(lua_State* L) {
        std::cout << "Executing Defend!" << std::endl;
        lua_pushstring(L, "FAILURE");
        return 1;
    }
    
    int lua_Patrol(lua_State* L) {
        std::cout << "Executing Patrol!" << std::endl;
        lua_pushstring(L, "SUCCESS");
        return 1;
    }
    
    int lua_LookAround(lua_State* L) {
        std::cout << "Executing LookAround!" << std::endl;
        lua_pushstring(L, "SUCCESS");
        return 1;
    }
    
    // Lua 스크립트 실행 함수
    void runLuaScript(lua_State* L, const std::string& script) {
        if (luaL_dofile(L, script.c_str()) != LUA_OK) {
            std::cerr << "Lua Error: " << lua_tostring(L, -1) << std::endl;
        }
    }
    
    // C++에서 Lua Behavior Tree 실행
    void runBehaviorTree(lua_State* L) {
        lua_getglobal(L, "runTree");
        if (lua_pcall(L, 0, 1, 0) != LUA_OK) {
            std::cerr << "Error calling runTree: " << lua_tostring(L, -1) << std::endl;
        } else {
            std::cout << "Behavior Tree Result: " << lua_tostring(L, -1) << std::endl;
        }
        lua_pop(L, 1);
    }
    
    int main() {
        lua_State* L = luaL_newstate();
        luaL_openlibs(L);
    
        // C++ 행동 함수 등록
        lua_register(L, "Attack", lua_Attack);
        lua_register(L, "Defend", lua_Defend);
        lua_register(L, "Patrol", lua_Patrol);
        lua_register(L, "LookAround", lua_LookAround);
    
        // Behavior Tree Lua 코드 실행
        runLuaScript(L, "behavior_tree.lua");
    
        // 트리 실행
        runBehaviorTree(L);
    
        lua_close(L);
        return 0;
    }
    

    📌 3. 실행 결과

    - [Selector] Root
      - [Sequence] Combat
        - [Action] Attack
        - [Action] Defend
      - [Selector] Idle
        - [Action] Patrol
        - [Action] LookAround
    
    Executing Attack!
    Executing Defend!
    Behavior Tree Result: FAILURE
    

    📌 구조 요약

    Lua: Behavior Tree를 정의하고, 행동 실행 시 C++을 호출
    C++: 행동 로직을 구현하고, Lua에서 호출할 수 있도록 함수 등록
    결과: Behavior Tree의 각 노드가 C++에서 실행되고 결과를 반환

    이제 Behavior Tree의 구조 설계는 Lua에서, 실제 행동 실행은 C++에서 담당하도록 완벽히 분리할 수 있어! 🚀

Designed by Tistory.