(如何在C++代码中调用Lua脚本的函数?)

http://chenlq.net/dev/cpp-why/50-half-performance-half-of-the-flexible-c-and-lua-hybrid-programming-how-lua-script-function-call-in-the-c-code.html
[50]一半是性能,一半是灵活——C++和Lua混合编程(如何在C++代码中调用Lua脚本的函数?)

Q:

在[49]一半是性能,一半是灵活——C++和Lua混合编程(如何在C++中执行Lua脚本?)中,我们介绍了如何在C++程序化中执行Lua脚本,然而很多时候,我们并不需要执行整个脚本,而是只要执行脚本中的某个函数完成某个功能就可以了,那么,如何在C++代码中执行Lua脚本中的函数呢?
A:

在C++代码中执行Lua脚本的函数,跟直接执行Lua脚本非常相似,只是因为函数的执行涉及到函数名的查找,参数以及返回值的传递,所以多了一些将参数和返回值出栈入栈的操作,而这些,Lua都提供了相应的函数(lua_getglobal()获取函数,lua_pushnumber()参数入栈,lua_call()调用函数)来完成,使用起来也非常方便。
我们来看一个具体的例子,在贪吃蛇游戏中,我们需要判断当前贪吃蛇到达的位置是否还在场景之内(isinscene()函数)。如果我们把这个判断逻辑以如下的形式固化在程序当中:
 

bool isinscene(int x,int y)
{
    if(x > 0 && x < 100
        && y > 0 && y < 100 )
    {
        return true;
    }
    else
    {
        return false;
    }
}

那么,整个程序就失去了灵活性,这个程序只能将场景限制在(0,0,100,100)范围之内,如果我们的需求发生了变化,场景变大或者是变小,我们不得不修改源代码,然后重新编译并发布给客户。
而如果是使用在C++代码中调用Lua函数来实现这种容易变化的逻辑,那么,整个程序将灵活得多。
要做到这一点,首先在C++代码中搭建起调用Lua函数的框架:
 

// 引入Lua需要的头文件
// 如果是C语言代码,extern "C"可以省略
extern "C"
{
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
};
#include <iostream>
// 判断x,y是否在场均内
bool inscene(lua_State* L,int x,int y)
{
    bool isin = false;  // 初始值,未在场景内
    if(nullptr != L)
    {
        // 根据函数名获得Lua中的函数
        lua_getglobal(L, "inscene");
        lua_pushnumber(L, x); // 参数一入栈
        lua_pushnumber(L, y); // 参数二入栈
        // 调用Lua中的inscene函数,
        // 这里的2,1表示两个输入参数,一个返回值
        lua_call(L, 2, 1);
        // 获得bool类型的返回值
        isin = lua_toboolean(L, -1);
        lua_pop(L, 1);// 将返回值出栈,恢复栈中的元素
    }
    return isin;
}
// C++程序执行Lua脚本
int main()
{
    // Lua解释器指针
    lua_State* L = nullptr;
    // 创建Lua解释器
    L = luaL_newstate();
    if(nullptr != L)
    {
        luaL_openlibs(L);// 打开Lua库
        // 执行Lua脚本snake.lua
        luaL_dofile(L, "snake.lua");
        int x = 10;
        int y = 40;
        // 调用Lua脚本中的函数
        bool isin = inscene(L, x, y);
        // 输出结果
        if(isin)
            std::cout<<x<<","<<y<<" is in the scene."<<std::endl;
        lua_close(L);// 关闭Lua
    }
    return 0;
}

这样,C++程序通过调用Lua脚本中的inscene函数来完成逻辑判断,相当于将游戏逻辑下放到了Lua脚本中,而Lua脚本的修改是相对比较容易的,只需要简单修改就可以直接使用(无需重新编译),可以很好地满足C++程序对于灵活性的要求。
这里,我们的snake.lua脚本是:
 

--判断点(x,y)是否在场景内
function inscene(x,y)
    local boolean isin = false;
    if x > 0 and x < 100
    and y > 0 and y < 100 then
    isin = true
    end
    return isin;
end

这样,我们就可以直接在Lua脚本中修改游戏逻辑,而无需对C++程序进行修改和重新编译。
最后还要提到的一点是,虽然C++程序和动态链接库结合的方式,一定程度上也可以让程序更加灵活(每个动态链库可以单独更新以适应新的需求),然而动态链接库的更新,仍然需要修改代码并重新编译,总体而言,仍旧没有Lua脚本灵活。所以,C++程序加上Lua脚本,比较适合于那些对性能要求不是太高,而对灵活性有更多要求的场景(比如游戏),而C++程序加上动态链接库的方式,更适合于那些对性能要求较高,而对灵活性要求不高的场景(比如大型软件)。总之,两种方式各有所长,将他们应用在各自最擅长的场景下,就最好了。
我们能在C++程序中执行Lua脚本或者调用Lua中的函数来增加C++程序的灵活性,反过来,那么我们是不是也可以在Lua脚本程序中调用C++的函数,来提高Lua脚本程序的性能呢?
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值