C++ 与 Lua 交互全链路解析:完整示例补充

118 阅读10分钟

引言

鉴于# C++ 与 Lua 交互全链路解析:基于Lua5.4.8的源码剖析文章篇幅过长,在此展示代码示例。

完整示例演示

示例结构

lua-cpp-game/ 
├── main.cpp # C++主程序 
├── game_logic.lua # Lua游戏逻辑 
├── skills.lua # 技能配置表 
├── characters.lua # 角色配置表 
└── CMakeLists.txt # 构建配置文件(可选)

示例代码

main.cpp

#include <iostream>
#include <string>
#include <vector>
#include <memory>
#include <chrono>
#include <thread>

extern "C" {
    #include "lua.h"
    #include "lualib.h"
    #include "lauxlib.h"
}

// 角色基类
class Character {
public:
    Character(const std::string& name, int health, int mana, int attack)
        : name(name), maxHealth(health), health(health), maxMana(mana), mana(mana), attack(attack), shield(0) {}
    
    std::string getName() const { return name; }
    int getHealth() const { return health; }
    void setHealth(int value) { 
        // 应用护盾
        if (shield > 0) {
            int damage = std::max(0, health - value);  // 计算实际伤害
            if (damage > 0) {
                if (shield >= damage) {
                    shield -= damage;
                    damage = 0;
                } else {
                    damage -= shield;
                    shield = 0;
                }
                value = health - damage;
            }
        }
        
        health = std::max(0, std::min(maxHealth, value));
        if (health == 0) {
            onDeath();
        }
    }
    int getMana() const { return mana; }
    void setMana(int value) { mana = std::max(0, std::min(maxMana, value)); }
    int getAttack() const { return attack; }
    int getShield() const { return shield; }
    void setShield(int value) { shield = std::max(0, value); }
    
    virtual void onDeath() {
        std::cout << name << " has been defeated!" << std::endl;
    }
    
    virtual void basicAttack(Character* target) {
        int damage = attack;
        target->setHealth(target->getHealth() - damage);
        std::cout << name << " attacks " << target->getName() << " for " << damage << " damage!" << std::endl;
    }

    // 从Lua表加载角色状态
    void loadState(lua_State* L, int index) {
        // 假设栈顶是角色状态表
        lua_getfield(L, index, "health");
        if (lua_isnumber(L, -1)) {
            health = lua_tointeger(L, -1);
        }
        lua_pop(L, 1);
        
        lua_getfield(L, index, "mana");
        if (lua_isnumber(L, -1)) {
            mana = lua_tointeger(L, -1);
        }
        lua_pop(L, 1);
        
        lua_getfield(L, index, "maxHealth");
        if (lua_isnumber(L, -1)) {
            maxHealth = lua_tointeger(L, -1);
        }
        lua_pop(L, 1);
        
        lua_getfield(L, index, "maxMana");
        if (lua_isnumber(L, -1)) {
            maxMana = lua_tointeger(L, -1);
        }
        lua_pop(L, 1);
        
        lua_getfield(L, index, "attack");
        if (lua_isnumber(L, -1)) {
            attack = lua_tointeger(L, -1);
        }
        lua_pop(L, 1);
        
        lua_getfield(L, index, "shield");
        if (lua_isnumber(L, -1)) {
            shield = lua_tointeger(L, -1);
        }
        lua_pop(L, 1);
    }

    // 保存角色状态到Lua表
    int saveState(lua_State* L) {
        // 创建新表
        lua_newtable(L);
        
        // 设置字段
        lua_pushinteger(L, health);
        lua_setfield(L, -2, "health");
        
        lua_pushinteger(L, mana);
        lua_setfield(L, -2, "mana");
        
        lua_pushinteger(L, maxHealth);
        lua_setfield(L, -2, "maxHealth");
        
        lua_pushinteger(L, maxMana);
        lua_setfield(L, -2, "maxMana");
        
        lua_pushinteger(L, attack);
        lua_setfield(L, -2, "attack");
        
        lua_pushinteger(L, shield);
        lua_setfield(L, -2, "shield");
        
        // 返回表在栈中的索引
        return lua_gettop(L);
    }

protected:
    std::string name;
    int maxHealth;
    int health;
    int maxMana;
    int mana;
    int attack;
    int shield;  // 新增护盾属性
};

// C++角色管理器
class CharacterManager {
public:
    static CharacterManager& getInstance() {
        static CharacterManager instance;
        return instance;
    }
    
    Character* createCharacter(const std::string& name, int health, int mana, int attack) {
        characters.push_back(std::make_unique<Character>(name, health, mana, attack));
        return characters.back().get();
    }
    
    void removeCharacter(Character* character) {
        for (auto it = characters.begin(); it != characters.end(); ++it) {
            if (it->get() == character) {
                characters.erase(it);
                break;
            }
        }
    }
    
private:
    CharacterManager() = default;
    std::vector<std::unique_ptr<Character>> characters;
};

// Lua与C++交互函数
static int lua_createCharacter(lua_State* L) {
    const char* name = luaL_checkstring(L, 1);
    int health = luaL_checkinteger(L, 2);
    int mana = luaL_checkinteger(L, 3);
    int attack = luaL_checkinteger(L, 4);
    
    Character* character = CharacterManager::getInstance().createCharacter(name, health, mana, attack);
    
    // 将C++对象指针存储为Lua轻量用户数据
    lua_pushlightuserdata(L, character);
    return 1;
}

static int lua_getCharacterName(lua_State* L) {
    Character* character = static_cast<Character*>(lua_touserdata(L, 1));
    if (!character) {
        luaL_error(L, "Invalid character userdata");
        return 0;
    }
    
    lua_pushstring(L, character->getName().c_str());
    return 1;
}

static int lua_getCharacterHealth(lua_State* L) {
    Character* character = static_cast<Character*>(lua_touserdata(L, 1));
    if (!character) {
        luaL_error(L, "Invalid character userdata");
        return 0;
    }
    
    lua_pushinteger(L, character->getHealth());
    return 1;
}

static int lua_setCharacterHealth(lua_State* L) {
    Character* character = static_cast<Character*>(lua_touserdata(L, 1));
    int health = luaL_checkinteger(L, 2);
    
    if (!character) {
        luaL_error(L, "Invalid character userdata");
        return 0;
    }
    
    character->setHealth(health);
    return 0;
}

static int lua_getCharacterMana(lua_State* L) {
    Character* character = static_cast<Character*>(lua_touserdata(L, 1));
    if (!character) {
        luaL_error(L, "Invalid character userdata");
        return 0;
    }
    
    lua_pushinteger(L, character->getMana());
    return 1;
}

static int lua_setCharacterMana(lua_State* L) {
    Character* character = static_cast<Character*>(lua_touserdata(L, 1));
    int mana = luaL_checkinteger(L, 2);
    
    if (!character) {
        luaL_error(L, "Invalid character userdata");
        return 0;
    }
    
    character->setMana(mana);
    return 0;
}

static int lua_getCharacterShield(lua_State* L) {
    Character* character = static_cast<Character*>(lua_touserdata(L, 1));
    if (!character) {
        luaL_error(L, "Invalid character userdata");
        return 0;
    }
    
    lua_pushinteger(L, character->getShield());
    return 1;
}

static int lua_setCharacterShield(lua_State* L) {
    Character* character = static_cast<Character*>(lua_touserdata(L, 1));
    int shield = luaL_checkinteger(L, 2);
    
    if (!character) {
        luaL_error(L, "Invalid character userdata");
        return 0;
    }
    
    character->setShield(shield);
    return 0;
}

static int lua_characterBasicAttack(lua_State* L) {
    Character* attacker = static_cast<Character*>(lua_touserdata(L, 1));
    Character* target = static_cast<Character*>(lua_touserdata(L, 2));
    
    if (!attacker || !target) {
        luaL_error(L, "Invalid character userdata");
        return 0;
    }
    
    attacker->basicAttack(target);
    return 0;
}

// 加载角色状态
static int lua_loadCharacterState(lua_State* L) {
    Character* character = static_cast<Character*>(lua_touserdata(L, 1));
    if (!character) {
        luaL_error(L, "Invalid character userdata");
        return 0;
    }
    
    // 第二个参数应为表
    if (!lua_istable(L, 2)) {
        luaL_error(L, "Argument #2 must be a table");
        return 0;
    }
    
    character->loadState(L, 2);
    return 0;
}

// 保存角色状态
static int lua_saveCharacterState(lua_State* L) {
    Character* character = static_cast<Character*>(lua_touserdata(L, 1));
    if (!character) {
        luaL_error(L, "Invalid character userdata");
        return 0;
    }
    
    // 保存状态到新表并返回
    int tableIndex = character->saveState(L);
    return 1;
}

// 从Lua表加载技能配置
static int lua_loadSkillConfig(lua_State* L) {
    // 假设栈顶是技能配置表
    if (!lua_istable(L, -1)) {
        luaL_error(L, "Top of stack must be a table");
        return 0;
    }
    
    // 遍历表中的所有技能
    lua_pushnil(L); // 初始键
    while (lua_next(L, -2) != 0) {
        // 键在索引-2,值在索引-1
        if (lua_istable(L, -1)) {
            const char* skillName = lua_tostring(L, -2);
            std::cout << "Loading skill: " << skillName << std::endl;
            
            // 获取技能属性
            lua_getfield(L, -1, "damage");
            int damage = lua_tointeger(L, -1);
            lua_pop(L, 1);
            
            lua_getfield(L, -1, "manaCost");
            int manaCost = lua_tointeger(L, -1);
            lua_pop(L, 1);
            
            lua_getfield(L, -1, "duration");
            int duration = lua_tointeger(L, -1);
            lua_pop(L, 1);
            
            lua_getfield(L, -1, "type");
            const char* type = lua_tostring(L, -1);
            lua_pop(L, 1);
            
            // 打印技能信息
            std::cout << "  Type: " << type << ", Damage: " << damage 
                      << ", Mana Cost: " << manaCost 
                      << ", Duration: " << duration << std::endl;
        }
        // 弹出值,保留键用于下次迭代
        lua_pop(L, 1);
    }
    
    return 0;
}

// 从Lua表加载角色配置
static int lua_loadCharacterConfig(lua_State* L) {
    // 假设栈顶是角色配置表
    if (!lua_istable(L, -1)) {
        luaL_error(L, "Top of stack must be a table");
        return 0;
    }
    
    // 遍历表中的所有角色
    lua_pushnil(L); // 初始键
    while (lua_next(L, -2) != 0) {
        // 键在索引-2,值在索引-1
        if (lua_istable(L, -1)) {
            const char* characterName = lua_tostring(L, -2);
            std::cout << "Loading character: " << characterName << std::endl;
            
            // 获取角色属性
            lua_getfield(L, -1, "health");
            int health = lua_tointeger(L, -1);
            lua_pop(L, 1);
            
            lua_getfield(L, -1, "mana");
            int mana = lua_tointeger(L, -1);
            lua_pop(L, 1);
            
            lua_getfield(L, -1, "attack");
            int attack = lua_tointeger(L, -1);
            lua_pop(L, 1);
            
            // 创建角色
            Character* character = CharacterManager::getInstance()
                .createCharacter(characterName, health, mana, attack);
            
            // 将角色指针存储在注册表中
            lua_pushlightuserdata(L, character);
            lua_setfield(L, LUA_REGISTRYINDEX, characterName);
            
            std::cout << "  Health: " << health << ", Mana: " 
                      << mana << ", Attack: " << attack << std::endl;
        }
        // 弹出值,保留键用于下次迭代
        lua_pop(L, 1);
    }
    
    return 0;
}

// 改进的wait函数实现
static int lua_wait(lua_State* L) {
    double seconds = luaL_checknumber(L, 1);
    
    // 仅在调试时打印等待信息
    if (seconds >= 0.5) {  // 只对较长的等待打印信息
        std::cout << "Waiting for " << seconds << " seconds..." << std::endl;
    }
    
    // 实际游戏中应该使用计时器系统,这里简化处理
    lua_yield(L, 0);  // 挂起协程
    return 0;
}

// 从文件加载并执行Lua脚本
bool executeLuaFile(lua_State* L, const std::string& filePath) {
    // 加载Lua文件
    if (luaL_loadfile(L, filePath.c_str()) != LUA_OK) {
        std::cerr << "Error loading Lua script: " << lua_tostring(L, -1) << std::endl;
        lua_pop(L, 1);  // 弹出错误消息
        return false;
    }
    
    // 执行Lua代码
    if (lua_pcall(L, 0, LUA_MULTRET, 0) != LUA_OK) {
        std::cerr << "Error executing Lua script: " << lua_tostring(L, -1) << std::endl;
        lua_pop(L, 1);  // 弹出错误消息
        return false;
    }
    
    return true;
}

int main() {
    // 创建Lua状态机
    lua_State* L = luaL_newstate();
    if (!L) {
        std::cerr << "Failed to create Lua state" << std::endl;
        return 1;
    }
    
    // 打开标准库
    luaL_openlibs(L);
    
    // 注册C++函数
    lua_register(L, "createCharacter", lua_createCharacter);
    lua_register(L, "getCharacterName", lua_getCharacterName);
    lua_register(L, "getCharacterHealth", lua_getCharacterHealth);
    lua_register(L, "setCharacterHealth", lua_setCharacterHealth);
    lua_register(L, "getCharacterMana", lua_getCharacterMana);
    lua_register(L, "setCharacterMana", lua_setCharacterMana);
    lua_register(L, "getCharacterShield", lua_getCharacterShield);
    lua_register(L, "setCharacterShield", lua_setCharacterShield);
    lua_register(L, "characterBasicAttack", lua_characterBasicAttack);
    lua_register(L, "loadCharacterState", lua_loadCharacterState);
    lua_register(L, "saveCharacterState", lua_saveCharacterState);
    lua_register(L, "loadSkillConfig", lua_loadSkillConfig);
    lua_register(L, "loadCharacterConfig", lua_loadCharacterConfig);
    
    // 注册改进的wait函数
    lua_register(L, "wait", lua_wait);
    
    // 从文件加载角色配置
    std::cout << "Loading character configurations..." << std::endl;
    if (!executeLuaFile(L, "characters.lua")) {
        lua_close(L);
        return 1;
    }
    
    // 从文件加载技能配置
    std::cout << "Loading skill configurations..." << std::endl;
    if (!executeLuaFile(L, "skills.lua")) {
        lua_close(L);
        return 1;
    }
    
    // 从文件加载主游戏逻辑
    std::cout << "Loading main game logic..." << std::endl;
    if (!executeLuaFile(L, "game_logic.lua")) {
        lua_close(L);
        return 1;
    }
    
    // 清理Lua状态机
    lua_close(L);
    
    return 0;
}        

game_logic.lua

-- 从注册表获取角色
local Hero = getmetatable(_G).__index.Hero
local Goblin = getmetatable(_G).__index.Goblin
local Wizard = getmetatable(_G).__index.Wizard
local Knight = getmetatable(_G).__index.Knight
local Dragon = getmetatable(_G).__index.Dragon

-- 游戏状态
local gameState = {
    combatants = {Hero, Goblin},
    currentTurn = 1,
    gameOver = false
}

-- 战斗系统
local CombatSystem = {}

-- 使用技能
function CombatSystem.useSkill(caster, target, skillName)
    local skill = Skills[skillName]
    if not skill then
        print("技能不存在: " .. skillName)
        return false
    end
    
    -- 检查魔法值
    if caster:getMana() < skill.manaCost then
        print(caster:getName() .. " 魔法值不足,无法使用 " .. skillName)
        return false
    end
    
    -- 消耗魔法值
    caster:setMana(caster:getMana() - skill.manaCost)
    
    -- 根据技能类型执行不同效果
    if skill.type == "offensive" then
        -- 攻击技能
        print(caster:getName() .. " 施放 " .. skillName .. " 对 " .. target:getName() .. " 造成 " .. skill.damage .. " 点伤害!")
        target:setHealth(target:getHealth() - skill.damage)
        
        -- 处理持续性效果(如燃烧)
        if skill.duration > 0 then
            print(target:getName() .. " 受到 " .. skill.damage/3 .. " 点持续伤害!")
            for i = 1, skill.duration do
                wait(1)
                if target:getHealth() > 0 then
                    local burnDamage = math.floor(skill.damage / 3)
                    print(target:getName() .. " 受到 " .. burnDamage .. " 点燃烧伤害!")
                    target:setHealth(target:getHealth() - burnDamage)
                end
            end
        end
    elseif skill.type == "healing" then
        -- 治疗技能
        local healAmount = -skill.damage  -- 伤害值为负表示治疗
        print(caster:getName() .. " 施放 " .. skillName .. " 恢复了 " .. healAmount .. " 点生命值!")
        caster:setHealth(caster:getHealth() + healAmount)
    elseif skill.type == "defensive" then
        -- 防御技能(护盾)
        print(caster:getName() .. " 施放 " .. skillName .. " 获得了 " .. skill.damage .. " 点护盾!")
        caster:setShield(skill.damage)
        
        -- 护盾持续时间
        if skill.duration > 0 then
            wait(skill.duration)
            if caster:getShield() > 0 then
                print(caster:getName() .. " 的护盾消失了!")
                caster:setShield(0)
            end
        end
    end
    
    return true
end

-- 简单的AI决策
function CombatSystem.aiDecision(aiCharacter, targets)
    -- 随机选择一个目标
    local targetIndex = math.random(1, #targets)
    local target = targets[targetIndex]
    
    -- 根据角色类型决定使用的技能
    if aiCharacter:getName() == "Goblin" then
        -- 哥布林总是进行普通攻击
        wait(0.5)
        characterBasicAttack(aiCharacter, target)
    elseif aiCharacter:getName() == "Wizard" then
        -- 法师优先使用魔法
        wait(0.5)
        if aiCharacter:getMana() >= Skills.Fireball.manaCost then
            CombatSystem.useSkill(aiCharacter, target, "Fireball")
        else
            characterBasicAttack(aiCharacter, target)
        end
    elseif aiCharacter:getName() == "Knight" then
        -- 骑士优先使用护盾
        wait(0.5)
        if aiCharacter:getMana() >= Skills.Shield.manaCost and aiCharacter:getShield() < 20 then
            CombatSystem.useSkill(aiCharacter, aiCharacter, "Shield")
        else
            characterBasicAttack(aiCharacter, target)
        end
    elseif aiCharacter:getName() == "Dragon" then
        -- 龙随机使用技能或普通攻击
        wait(0.5)
        local rand = math.random(1, 3)
        if rand == 1 and aiCharacter:getMana() >= Skills.Fireball.manaCost then
            CombatSystem.useSkill(aiCharacter, target, "Fireball")
        elseif rand == 2 and aiCharacter:getMana() >= Skills.Lightning.manaCost then
            CombatSystem.useSkill(aiCharacter, target, "Lightning")
        else
            characterBasicAttack(aiCharacter, target)
        end
    end
end

-- 战斗回合
function CombatSystem.executeTurn()
    local attacker = gameState.combatants[gameState.currentTurn]
    
    if attacker:getHealth() <= 0 then
        -- 如果攻击者已死亡,跳过此回合
        print(attacker:getName() .. " 已死亡,跳过回合")
        gameState.currentTurn = gameState.currentTurn % #gameState.combatants + 1
        return
    end
    
    print("\n=== " .. attacker:getName() .. "'s 回合 ===")
    
    -- 确定目标列表
    local targets = {}
    for i, combatant in ipairs(gameState.combatants) do
        if combatant ~= attacker and combatant:getHealth() > 0 then
            table.insert(targets, combatant)
        end
    end
    
    -- 玩家控制的角色
    if attacker:getName() == "Hero" then
        -- 简单模拟玩家输入
        wait(0.5)
        
        -- 随机选择一个技能或普通攻击
        local rand = math.random(1, 4)
        if rand == 1 and attacker:getMana() >= Skills.Fireball.manaCost then
            local targetIndex = math.random(1, #targets)
            CombatSystem.useSkill(attacker, targets[targetIndex], "Fireball")
        elseif rand == 2 and attacker:getMana() >= Skills.Heal.manaCost and attacker:getHealth() < attacker:getHealth() * 0.5 then
            CombatSystem.useSkill(attacker, attacker, "Heal")
        elseif rand == 3 and attacker:getMana() >= Skills.Shield.manaCost and attacker:getShield() < 30 then
            CombatSystem.useSkill(attacker, attacker, "Shield")
        else
            local targetIndex = math.random(1, #targets)
            characterBasicAttack(attacker, targets[targetIndex])
        end
    else
        -- AI控制的角色
        CombatSystem.aiDecision(attacker, targets)
    end
    
    -- 检查战斗是否结束
    local allEnemiesDead = true
    for i, combatant in ipairs(gameState.combatants) do
        if combatant ~= Hero and combatant:getHealth() > 0 then
            allEnemiesDead = false
            break
        end
    end
    
    if allEnemiesDead then
        print("\n=== 战斗胜利! ===")
        gameState.gameOver = true
        return
    end
    
    local heroDead = Hero:getHealth() <= 0
    if heroDead then
        print("\n=== 战斗失败! ===")
        gameState.gameOver = true
        return
    end
    
    -- 切换到下一回合
    gameState.currentTurn = gameState.currentTurn % #gameState.combatants + 1
end

-- 游戏主循环
function runGame()
    print("\n=== 游戏开始 ===")
    
    -- 展示初始状态
    print("\n=== 初始状态 ===")
    for i, combatant in ipairs(gameState.combatants) do
        print(combatant:getName() .. ": 生命值=" .. combatant:getHealth() .. ", 魔法值=" .. combatant:getMana())
    end
    
    -- 战斗循环
    while not gameState.gameOver do
        wait(1)
        CombatSystem.executeTurn()
        
        -- 展示当前状态
        print("\n=== 当前状态 ===")
        for i, combatant in ipairs(gameState.combatants) do
            local status = combatant:getHealth() > 0 and "存活" or "死亡"
            print(combatant:getName() .. ": 生命值=" .. combatant:getHealth() .. ", 魔法值=" .. combatant:getMana() .. ", 护盾=" .. combatant:getShield() .. ", 状态=" .. status)
        end
    end
    
    print("\n=== 游戏结束 ===")
end

-- 状态管理示例
function testStateManagement()
    print("\n=== 状态管理测试 ===")
    
    -- 保存初始状态
    local heroState = {}
    heroState = saveCharacterState(Hero)
    
    local enemyState = {}
    enemyState = saveCharacterState(Goblin)
    
    print("\n=== 保存的状态 ===")
    print("Hero Health: " .. heroState.health)
    print("Hero Mana: " .. heroState.mana)
    print("Enemy Health: " .. enemyState.health)
    
    -- 进行一些操作
    print("\n=== 进行战斗操作 ===")
    characterBasicAttack(Hero, Goblin)
    wait(0.5)
    CombatSystem.useSkill(Hero, Goblin, "Fireball")
    wait(0.5)
    
    -- 展示当前状态
    print("\n=== 操作后的状态 ===")
    print("Hero Health: " .. Hero:getHealth())
    print("Hero Mana: " .. Hero:getMana())
    print("Enemy Health: " .. Goblin:getHealth())
    
    -- 恢复状态
    print("\n=== 恢复到保存的状态 ===")
    loadCharacterState(Hero, heroState)
    loadCharacterState(Goblin, enemyState)
    
    -- 展示恢复后的状态
    print("\n=== 恢复后的状态 ===")
    print("Hero Health: " .. Hero:getHealth())
    print("Hero Mana: " .. Hero:getMana())
    print("Enemy Health: " .. Goblin:getHealth())
end

-- 测试不同的战斗场景
function testMultipleScenarios()
    print("\n=== 多场景测试 ===")
    
    -- 测试英雄 vs 哥布林
    print("\n=== Hero vs Goblin ===")
    gameState.combatants = {Hero, Goblin}
    gameState.currentTurn = 1
    gameState.gameOver = false
    runGame()
    
    wait(2)
    
    -- 测试英雄 vs 法师
    print("\n=== Hero vs Wizard ===")
    Hero:setHealth(100)
    Hero:setMana(50)
    Wizard:setHealth(50)
    Wizard:setMana(100)
    gameState.combatants = {Hero, Wizard}
    gameState.currentTurn = 1
    gameState.gameOver = false
    runGame()
    
    wait(2)
    
    -- 测试英雄 vs 骑士
    print("\n=== Hero vs Knight ===")
    Hero:setHealth(100)
    Hero:setMana(50)
    Knight:setHealth(150)
    Knight:setMana(30)
    gameState.combatants = {Hero, Knight}
    gameState.currentTurn = 1
    gameState.gameOver = false
    runGame()
    
    wait(2)
    
    -- 测试英雄 vs 龙 (可能会失败)
    print("\n=== Hero vs Dragon (挑战!) ===")
    Hero:setHealth(100)
    Hero:setMana(50)
    Dragon:setHealth(300)
    Dragon:setMana(150)
    gameState.combatants = {Hero, Dragon}
    gameState.currentTurn = 1
    gameState.gameOver = false
    runGame()
}

-- 运行测试
testStateManagement()
wait(2)
testMultipleScenarios()

print("\n=== 所有测试完成 ===")    

skills.lua

-- 技能配置表
Skills = {
    Fireball = {
        damage = 30,
        manaCost = 20,
        duration = 3,
        type = "offensive"
    },
    
    Heal = {
        damage = -40,  -- 负数表示治疗
        manaCost = 15,
        duration = 0,
        type = "healing"
    },
    
    Lightning = {
        damage = 45,
        manaCost = 30,
        duration = 0,
        type = "offensive"
    },
    
    Shield = {
        damage = 50,  -- 护盾值
        manaCost = 25,
        duration = 10,
        type = "defensive"
    },
    
    Poison = {
        damage = 10,
        manaCost = 15,
        duration = 5,
        type = "offensive"
    }
}

-- 加载技能配置
loadSkillConfig(Skills)    

characters.lua

-- 角色配置表
Characters = {
    Hero = {
        health = 100,
        mana = 50,
        attack = 15
    },
    
    Goblin = {
        health = 70,
        mana = 0,
        attack = 10
    },
    
    Wizard = {
        health = 50,
        mana = 100,
        attack = 8
    },
    
    Knight = {
        health = 150,
        mana = 30,
        attack = 20
    },
    
    Dragon = {
        health = 300,
        mana = 150,
        attack = 25
    }
}

-- 加载角色配置
loadCharacterConfig(Characters)       

CMakeLists.txt

cmake_minimum_required(VERSION 3.10)
project(LuaCppGame)

# 设置C++标准
set(CMAKE_CXX_STANDARD 17)

# 查找Lua库
find_package(Lua REQUIRED)
include_directories(${LUA_INCLUDE_DIR})

# 添加可执行文件
add_executable(lua_game main.cpp)

# 链接Lua库
target_link_libraries(lua_game ${LUA_LIBRARIES})

# 复制Lua脚本到构建目录
file(COPY characters.lua skills.lua game_logic.lua DESTINATION ${CMAKE_BINARY_DIR})