What is Lua ?
Lua is a lightweight and extensible scripting language. It’s been building a lot of hype in the Game Development World and I wanted to try it to see what the buzz was all about. I must say it looks pretty nice so far.
This tutorial
In this tutorial we will create a basic hello world program. After that I will show how you can call C++ functions from Lua and call Lua functions from C++. Doing so we will cover the basics about the Lua stack. Why write another Lua tutorial you might ask ? Simply because I wanted to see if I could write a tutorial. Don’t know if I did a good job or not, leave a comment to let me know :)
Getting started with Lua
(Using Visual C++ Express 2005)
- Download lua5_1_1_Sources.zip from LuaBinaries
- Open lua5.1/mak.vs2005/lua5.1.sln and build the project lua5.1_lib
- Create a new project and name it Lua_Tutorial1
- Copy lua5.1/lib/static/lua5.1.lib and lua5.1/lua5.1/include/* in the Lua_Tutorial1 folder
- In VS C++ Express 2005 : Project > Lua_Tutorial1 Properties
Configuration Properties > Linker > Input
Additional Dependencies = $(ProjectDir)/lua5.1.lib (Doing this, we link our static library to our Project)
Ignore Specific Library = LIBCMT.lib
Once our project is ready, we can start coding !
Hello World in Lua
In this example we will print execute a lua file that print Hello World to the console
#include "stdio.h"
/* We include lua's hpp header. Lua is written in ANSI C. To use C with C++ we need to use extern "C". lua.hpp does just that.
extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}
*/
#include "lua.hpp"
int main ( int argc, char *argv[] )
{
// The lua interpreter. The interpreter is going to parse and execute our test.lua file
lua_State* lua_VM;
// We initialise the interpreter and load lua libraries
lua_VM = lua_open();
luaL_openlibs(lua_VM);
// This is where the party get started. We load and execute test.lua
luaL_dofile(lua_VM, "test.lua");
// Let's close the lua interpreter, we're done for the day..
lua_close(lua_VM);
// Pause and finish up
printf( "Press enter to exit…" );
getchar();
return 0;
}
Here’s what test.lua looks like:
-- Hello World in Lua
print "Hello World!"
That’s pretty simple! Now let’s have some more fun with lua!
Fun with Lua and HexEngine
Let’s do something fun and a little bit more complex. I’ll add the following “feature” in HexEngine: I will execute a .lua file that calls a C++ function. This function will call a Lua function to do some calculation and return the result. Then I will then display the result at the mouse position… I didn’t say useful, I said fun and a little bit more complex :) This example is to show how to call C++ function from Lua and how to call Lua function from C++.
// The lua interpreter
lua_State* luaVm = NULL;
// We declare our functions
int lua_mousePos ( int x, int y );
int l_showMousePos(lua_State *L);
// ...
// The initialisation of HexEngine
bool CHexEngine::initHexEngine()
{
// We initialise the interpreter and load lua libraries
luaVm = lua_open();
luaL_openlibs(luaVm);
// We register our function. With this we will be able to call it from Lua.b
lua_register(luaVm, "showMousePos", l_showMousePos);
// ...
}
// The draw function of HexEngine
void CHexEngine::drawHexEngine()
{
// We load and execute test.lua
luaL_dofile(luaVm, "test.lua");
// ...
}
//Now that we prepared the soils, let's get our hands dirty !
//This is the function that is going to call our lua function
char * lua_mousePos ( int x, int y )
{
// By calling lua_getglobal, we push our lua function on the stack
lua_getglobal(luaVm, "mousePos");
// We push x, the first parameter that receive our function, on the stack
lua_pushnumber(luaVm, x);
// We push y, the second parameter, on the stack
lua_pushnumber(luaVm, x);
// We call the function with 2 argument and 1 return value
lua_call(luaVm, 2, 1);
// We get the result and remove (pop) the value from the stack.
char * strPos = (char*)lua_tointeger(luaVm, -1);
lua_pop(luaVm, 1);
return strPos;
}
// Our C++ function that we registered earlier
int l_showMousePos(lua_State *L)
{
// We get our mouse position
CPosition mousePos = CHexEngine::getInstance()->mouse.position;
// We write, at the mouse position, the result of our lua function
CHexEngine::getInstance()->write(mousePos, CColor( 0xFFFFFF ), "%s", lua_mousePos((int)mousePos.x, (int)mousePos.y ));
/* You may ask "Why didn't you declare this function as void if you're not returning any value".
By returning 0, I'm telling Lua that I did not add anything on the stack.
If I wanted I could have had 2 values on the stack :
lua_pushnumber(L, 42);
lua_pushnumber(L, 21);
and return 2.
And in lua I would have called my function like this :
var1, var2 = showXPos();
With this, var1 = 42 and var2 = 21
*/
return 0;
}
-- Our Lua function
function mousePos ( x, y )
tileSize = 32;
return string.format("%dx%d", ((x - (x % tileSize)) / tileSize), ((y - (y % tileSize)) / tileSize) ) ;
end
-- We call our C++ function
showMousePos();
That’s it ! For those that noticed, the title was Lua _part 1_. Because this tutorial covered the base, it didn’t really show how you could really use Lua in your game. So in the next part, I’ll try to show that. Stay tuned !
Resources
This tutorial was inspired by Tony’s Lua tutorials over at GameDevGeek.com. I wrote my own because I wanted to see if I could do it and because I wanted to extended on it for part 2.