• Announcement: Lua.org now officially recommends this forum as a meeting place for the Lua community
  • The forum is currently open to new registrations. The registration will close for a short period of time when reaching 500 active members, to upgrade the server resources.

How to use LUA as a script for NPC In c++ game (2 Viewers)

94programmer

Newcomer
Joined
Nov 17, 2020
Messages
1
Reaction score
2
Hello, I was reading a lot on the internet but I am still looking for an answer, I dont expect a solution from you, just a simple answers or a books, online tutorials which will help me to solve that problem. Well I am coding a game for fun in c++, SFML, where I load entities like NPC, tiles from JSON file. Now I discovered LUA to use it as a scripts for s NPC and tiles and make them able to move, open dialog box etc. But I totally dont have idea how to make it. First of all I embed LUA to c++ and everything works well, I passed simple tutorials for begginers to know what exactly lua is, but I have no idea and I cant find on internet good sources which will help me with communicaton my entities objects from c++ and lua scripts and vice versa, like idk how to exactly make that communication well between entities and scripts and c++, can you help me a bit somehow?
 

Simon

Newcomer
Joined
Nov 19, 2020
Messages
6
Reaction score
0
Age
23
Location
Netherlands
How did you embed Lua to C++? I'm struggling with that.
 

stetre

Member
Rank: I
Joined
Jan 8, 2020
Messages
45
Reaction score
28
Location
Italy
Website
github.com
Forget online tutorials. The ultimate resource for understanding this topic is part 4 of the PIL book (Programming in Lua), the part that deals with the C-API. If you cannot afford the latest edition, the first edition is available on line for free and is in large part still relevant.

That said, the basic idea of embedding Lua is that you have functionalities written in C (or C++), and you want the user to be able to execute them from a script. To do this, you create a Lua state, enrich it with custom Lua functions that you implement in C/C++, and then load and execute the user script in that Lua state. Whenever the user calls one of your custom Lua functions, the corresponding C/C++ implementation is executed, and this is where you implement the fuctionalities you want to expose.

The linkage between the Lua function call and its C/C++ implementation is done via the C-API. This is what you need to learn to master for this sort of tasks, and the above mentioned book is the best resource for studying it.
 

stetre

Member
Rank: I
Joined
Jan 8, 2020
Messages
45
Reaction score
28
Location
Italy
Website
github.com
Just to provide something to start with hands-on, I wrote a small working example of embedding Lua in C (changes for C++ are trivial: a different header to include, and a different compiler to call).

The main.c file is the application. It creates a Lua state, adds a couple of custom functions to it, and then execute in it the user script that calls those function. The script name is passed as first argument to the application.

C:
/*
* main.c - the application
*/
#include <stdlib.h>
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
// If you are using C++, replace the above 3 headers with:
//#include <lua.hpp>

static int Square(lua_State *L)
/* Implementation of the function that the user will see in Lua as 'square()' */
    {
    double d = luaL_checknumber(L, 1); /* get the first function argument */
    lua_pushnumber(L, d*d);     /* compute the result and push it on the stack */
    return 1;                   /* no. of results */
    }

static int Sum(lua_State *L)
/* Implementation of the function that the user will see in Lua as 'sum()' */
    {
    double a = luaL_checknumber(L, 1); /* get the first function argument */
    double b = luaL_checknumber(L, 2); /* get the second function argument */
    lua_pushnumber(L, a+b);     /* compute the result and push it on the stack */
    return 1;                   /* no. of results */
    }

int main (int argc, char** argv) //, char** env)
    {
    lua_State *L;
    char* fname;

    if(argc!=2)
        { printf("Usage: %s <filename>\n", argv[0]); exit(0); }
    fname = argv[1]; /* the name of the user script */

    L = luaL_newstate();  /* create a new Lua state */
    luaL_openlibs(L);     /* add to it the standard Lua libraries */

    /* add to it the custom functions (see also luaL_setfuncs) */
    lua_pushcfunction(L, Square); /* push function on the stack */
    lua_setglobal(L, "square");   /* assign to global var */
    lua_pushcfunction(L, Sum);    /* push function on the stack */
    lua_setglobal(L, "sum");      /* assign to global var */

    /* push the user script on the stack and execute it: */
    if(luaL_loadfile(L, fname))
        luaL_error(L,"cannot run file: %s\n", lua_tostring(L,-1));
    if(lua_pcall(L, 0, 0, 0) != LUA_OK)
        {
        printf("Script Error!\n%s\n", lua_tostring(L, -1));
        lua_close(L);
        exit(EXIT_FAILURE);
        }

    lua_close(L); /* finally delete the Lua state */
    return 0;
    }

A user script could be something simple like:

Lua:
-- script.lua - the user script
print(square(2))
print(sum(3, 7))

To build (compile and link) the application from the command line:

Bash:
$ cc -o myapp main.c -llua -lm -ldl

To execute:

Bash:
$ ./myapp script.lua

These command-line commands should work on any POSIX system (GNU/Linux, MSYS2, Cygwin, perhaps MacOS...). If you are using an IDE you are on your own, but it should not be difficult to figure out how to do the same thing (build and execute).
 

Simon

Newcomer
Joined
Nov 19, 2020
Messages
6
Reaction score
0
Age
23
Location
Netherlands
Just to provide something to start with hands-on, I wrote a small working example of embedding Lua in C (changes for C++ are trivial: a different header to include, and a different compiler to call).

The main.c file is the application. It creates a Lua state, adds a couple of custom functions to it, and then execute in it the user script that calls those function. The script name is passed as first argument to the application.

C:
/*
* main.c - the application
*/
#include <stdlib.h>
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
// If you are using C++, replace the above 3 headers with:
//#include <lua.hpp>

static int Square(lua_State *L)
/* Implementation of the function that the user will see in Lua as 'square()' */
    {
    double d = luaL_checknumber(L, 1); /* get the first function argument */
    lua_pushnumber(L, d*d);     /* compute the result and push it on the stack */
    return 1;                   /* no. of results */
    }

static int Sum(lua_State *L)
/* Implementation of the function that the user will see in Lua as 'sum()' */
    {
    double a = luaL_checknumber(L, 1); /* get the first function argument */
    double b = luaL_checknumber(L, 2); /* get the second function argument */
    lua_pushnumber(L, a+b);     /* compute the result and push it on the stack */
    return 1;                   /* no. of results */
    }

int main (int argc, char** argv) //, char** env)
    {
    lua_State *L;
    char* fname;

    if(argc!=2)
        { printf("Usage: %s <filename>\n", argv[0]); exit(0); }
    fname = argv[1]; /* the name of the user script */

    L = luaL_newstate();  /* create a new Lua state */
    luaL_openlibs(L);     /* add to it the standard Lua libraries */

    /* add to it the custom functions (see also luaL_setfuncs) */
    lua_pushcfunction(L, Square); /* push function on the stack */
    lua_setglobal(L, "square");   /* assign to global var */
    lua_pushcfunction(L, Sum);    /* push function on the stack */
    lua_setglobal(L, "sum");      /* assign to global var */

    /* push the user script on the stack and execute it: */
    if(luaL_loadfile(L, fname))
        luaL_error(L,"cannot run file: %s\n", lua_tostring(L,-1));
    if(lua_pcall(L, 0, 0, 0) != LUA_OK)
        {
        printf("Script Error!\n%s\n", lua_tostring(L, -1));
        lua_close(L);
        exit(EXIT_FAILURE);
        }

    lua_close(L); /* finally delete the Lua state */
    return 0;
    }

A user script could be something simple like:

Lua:
-- script.lua - the user script
print(square(2))
print(sum(3, 7))

To build (compile and link) the application from the command line:

Bash:
$ cc -o myapp main.c -llua -lm -ldl

To execute:

Bash:
$ ./myapp script.lua

These command-line commands should work on any POSIX system (GNU/Linux, MSYS2, Cygwin, perhaps MacOS...). If you are using an IDE you are on your own, but it should not be difficult to figure out how to do the same thing (build and execute).

Thx! :D
 

stetre

Member
Rank: I
Joined
Jan 8, 2020
Messages
45
Reaction score
28
Location
Italy
Website
github.com
You're welcome ;)

For completeness, let's add a similar example, this time extending Lua from C. That is, we write a Lua module in C and load it from Lua using require( ).

The mymodule.c code implements the module. Notice that it does not contain a main() because it is a library. Instead, it has an initialization function named luaopen_mymodule( ) that Lua calls when the module is loaded (that is, require( )'d).

C:
/*
 * mymodule.c - a Lua module written in C
 */
#include <stdlib.h>
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>

#define MYMODULE_VERSION "1.0"

static int Square(lua_State *L)
/* Implementation of the function that the user will see in Lua as 'square()' */
    {
    double d = luaL_checknumber(L, 1); /* get the first function argument */
    lua_pushnumber(L, d*d);     /* compute the result and push it on the stack */
    return 1;                   /* no. of results */
    }

static int Sum(lua_State *L)
/* Implementation of the function that the user will see in Lua as 'sum()' */
    {
    double a = luaL_checknumber(L, 1); /* get the first function argument */
    double b = luaL_checknumber(L, 2); /* get the second function argument */
    lua_pushnumber(L, a+b);     /* compute the result and push it on the stack */
    return 1;                   /* no. of results */
    }

/* This struct contains a list of functions, in pairs (name, C function): */
static const struct luaL_Reg Functions[] =
    {
        { "square", Square },
        { "sum", Sum },
        { NULL, NULL }  // sentinel, denotes the end of the list
    };

int luaopen_mymodule(lua_State *L)
/* This function is executed by Lua when the module is required by a Lua script.
 * It creates a table and inserts the module's functions and variables in it.
 * Note that this function must be named 'luaopen_xxxx', where xxxx is the name of
 * the module. This convention allows Lua to locate it when loading the library.
 */
    {
    lua_newtable(L); /* this is the module table */

    /* Set mymodule._VERSION to a string containing the module's version */
    lua_pushstring(L, "MyModule "MYMODULE_VERSION);
    lua_setfield(L, -2, "_VERSION");

    /* add the functions listed in the Functions struct */
    luaL_setfuncs(L, Functions, 0);
    return 1;
    }



An example script that uses the module could be something like this:

Lua:
-- script.lua - the user script
local mymodule = require("mymodule")

print(mymodule._VERSION)
print(mymodule.square(2))
print(mymodule.sum(3, 7))

Build the library with ...

Bash:
$ cc -shared -o mymodule.so -llua mymodule.c

... and execute the script with the standard Lua interpreter...

Bash:
$ lua script.lua
 

Simon

Newcomer
Joined
Nov 19, 2020
Messages
6
Reaction score
0
Age
23
Location
Netherlands
You're welcome ;)

For completeness, let's add a similar example, this time extending Lua from C. That is, we write a Lua module in C and load it from Lua using require( ).

The mymodule.c code implements the module. Notice that it does not contain a main() because it is a library. Instead, it has an initialization function named luaopen_mymodule( ) that Lua calls when the module is loaded (that is, require( )'d).

C:
/*
* mymodule.c - a Lua module written in C
*/
#include <stdlib.h>
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>

#define MYMODULE_VERSION "1.0"

static int Square(lua_State *L)
/* Implementation of the function that the user will see in Lua as 'square()' */
    {
    double d = luaL_checknumber(L, 1); /* get the first function argument */
    lua_pushnumber(L, d*d);     /* compute the result and push it on the stack */
    return 1;                   /* no. of results */
    }

static int Sum(lua_State *L)
/* Implementation of the function that the user will see in Lua as 'sum()' */
    {
    double a = luaL_checknumber(L, 1); /* get the first function argument */
    double b = luaL_checknumber(L, 2); /* get the second function argument */
    lua_pushnumber(L, a+b);     /* compute the result and push it on the stack */
    return 1;                   /* no. of results */
    }

/* This struct contains a list of functions, in pairs (name, C function): */
static const struct luaL_Reg Functions[] =
    {
        { "square", Square },
        { "sum", Sum },
        { NULL, NULL }  // sentinel, denotes the end of the list
    };

int luaopen_mymodule(lua_State *L)
/* This function is executed by Lua when the module is required by a Lua script.
* It creates a table and inserts the module's functions and variables in it.
* Note that this function must be named 'luaopen_xxxx', where xxxx is the name of
* the module. This convention allows Lua to locate it when loading the library.
*/
    {
    lua_newtable(L); /* this is the module table */

    /* Set mymodule._VERSION to a string containing the module's version */
    lua_pushstring(L, "MyModule "MYMODULE_VERSION);
    lua_setfield(L, -2, "_VERSION");

    /* add the functions listed in the Functions struct */
    luaL_setfuncs(L, Functions, 0);
    return 1;
    }



An example script that uses the module could be something like this:

Lua:
-- script.lua - the user script
local mymodule = require("mymodule")

print(mymodule._VERSION)
print(mymodule.square(2))
print(mymodule.sum(3, 7))

Build the library with ...

Bash:
$ cc -shared -o mymodule.so -llua mymodule.c

... and execute the script with the standard Lua interpreter...

Bash:
$ lua script.lua

Wow, I did not ewen know it was possible o_O Amazing!
 

stetre

Member
Rank: I
Joined
Jan 8, 2020
Messages
45
Reaction score
28
Location
Italy
Website
github.com
Not only it is possible, it is what makes Lua useful as a language!

As you may well know, Lua is a very small language with a minimal set of functionalities. The extension mechanism is what allow people to write bindings to C and C++ libraries that provide the features that they need, but that they can't find in native Lua (I've written a few myself).
 

dinsdale247

Moderator
Staff member
Community Patron
Creator of WinLua
Joined
Nov 17, 2020
Messages
73
Reaction score
31
Location
Victoria BC
Website
winlua.net
 
Top