準備弄cocos2dx的lua,搗騰一下lua,留點印記給後面的童鞋參考。(俺也是半吊子,如果看官發現啥不妥的地方,請使勁噴。我全接受)
1、版本:這是個坑。
首先 pil (programming in lua)國人(似乎是風雲大大)翻譯的版本是5.0 有點低了。
cocos2dx 2.15用的是lua 5.1 ,
最新的lua 是5.2 ,
最新的pil 3rd 也是5.2;
5.0 ;5.1; 5.2的函數變化了不少,剛接觸的時候會遇到即使是copy的代碼也跑錯的時候,就看你的code和lua環境是否一緻吧。 網上大多代碼示例都是5.0的,要稍加修改。
2、看書,lua不大,也不複雜。如果不是研究lua代碼實作的話,入門還是比較快的。
先把pil仔細翻幾遍,對文法都ok,然後再看 C 綁定的部分。這塊主要是metatable __index __newindex的幾個概念搞清晰。即可。
3、c,c++
這個其實就是用到上面(2)提到的技巧而已,本質上就是lua來通過glue代碼間接操作C++的class而已。
廢話不多說,趕着睡覺呢。。。。其實也說不清。看代碼吧。加了詳細的注釋了。
makefile
all:
g++ -g3 -o cheneeout chenee.cpp -llua
clean:
rm -R *dSYM *out
chenee.lua
print "test lua access C++ Class"
local a = Animal("dog")
--local a = Animal.creat("dog")
a:setAge(100)
a:sound()
print ("age is :" .. a:getAge())
chenee.cpp
//
//@chenee:this Demo showing how to manipulate the C++ class with LUA
// LUA = the moon
//
#include <stdio.h>
#include <string>
#include <iostream>
extern "C"{
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
}
//@chenee: to dump the lua stack
static void stackDump(lua_State * L)
{
int i;
int top = lua_gettop(L); /* depth of the stack */
for (i = 1; i <= top; i++) { /* repeatforeachlevel */
int t = lua_type(L, i);
switch (t) {
case LUA_TSTRING:{ /* strings */
printf("'%s'", lua_tostring(L, i));
break;
}
case LUA_TBOOLEAN:{ /* booleans */
printf(lua_toboolean(L, i) ? "true" : "false");
break;
}
case LUA_TNUMBER:{ /* numbers */
printf("%g", lua_tonumber(L, i));
break;
}
default:{ /* other values */
printf("%s", lua_typename(L, t));
break;
}
}
printf(" "); /* put a separator */
}
printf("\n"); /* end the listing */
}
using namespace std;
//
//@chenee: the class to be deal with;
//
class Animal{
public:
Animal(std::string name):age(0){ this->name = name;};
void setAge(int age) { this->age = age;};
int getAge(){ return this->age;};
void sound(){ cout << " -- Animal name: " << this->name << " and it's Age:"<< this->age << endl;};
private:
string name;
int age;
};
//
//@chenee: this class used as a tool to expose interfaces to lua
//
class LuaAnimal{
static const string className;
static const luaL_reg methods[];
static const luaL_reg methods_f[];
static int creat(lua_State *L){
string name (lua_tostring(L,1));
Animal *a = new Animal(name);
void **p = (void**)lua_newuserdata(L,sizeof(void*));
*p = a;
luaL_getmetatable(L, className.c_str());
lua_setmetatable(L, -2);
return 1;
}
static int gc_animal(lua_State *L) {
Animal *a = (Animal*)(*(void**)lua_touserdata(L,1));
delete a;
// cout << "Gc ....." << endl;
return 0;
}
static Animal* getAnimal(lua_State *L){
luaL_checktype(L,1,LUA_TUSERDATA);
void *ud = luaL_checkudata(L,1,className.c_str());
if(!ud){
luaL_typerror(L,1,className.c_str());
}
return *(Animal**)ud;
}
static int sound(lua_State *L){
Animal *a = getAnimal(L);
a->sound();
return 1;
}
static int setAge(lua_State *L){
Animal *a = getAnimal(L);
double age = luaL_checknumber(L, 2);
a->setAge(int(age));
return 0;
}
static int getAge(lua_State *L){
Animal *a = getAnimal(L);
int age = a->getAge();
lua_pushinteger(L, age);
return 1;
}
public:
static void Register(lua_State* L) {
//1: new methods talbe for L to save functions
lua_newtable(L);
int methodtable = lua_gettop(L);
//2: new metatable for L to save "__index" "__newindex" "__gc" "__metatable" ...
luaL_newmetatable(L, className.c_str());
int metatable = lua_gettop(L);
//3: metatable["__metatable"] = methodtable
lua_pushliteral(L, "__metatable");
lua_pushvalue(L, methodtable);
lua_settable(L, metatable); // hide metatable from Lua getmetatable()
//4: metatable["__index"] = methodtable
lua_pushliteral(L, "__index");
lua_pushvalue(L, methodtable);
lua_settable(L, metatable);
//5: metatable["__gc"] = gc_animal
lua_pushliteral(L, "__gc");
lua_pushcfunction(L, gc_animal);
lua_settable(L, metatable);
lua_pop(L, 1); // drop metatable
//6: for objct:
// name == 0 set object function to "methods"
//eg:Animal a = Animal("xx");
//a:func() in this "methods" table;
luaL_openlib(L, 0, methods, 0); // fill methodtable
lua_pop(L, 1); // drop methodtable
//7.1: for Class:
//name = "classname" , so this set Class function to "methods_f"
//eg:Animal a = Animal:creat("xx");
//Animal:creat() in this "methods_f" tables;
// luaL_openlib(L, className.c_str(), methods_f, 0);
//7.2: for Class:
//add global function "Classname", so we Animal() is a global function now
//Animal a = Animal("xx");
//function Animal()in lua will call "creat" in C++
lua_register(L, className.c_str(), creat);
}
};
const string LuaAnimal::className = "Animal";
const luaL_reg LuaAnimal::methods[] = {
{"sound", LuaAnimal::sound},
{"setAge", LuaAnimal::setAge},
{"getAge", LuaAnimal::getAge},
{"__gc", LuaAnimal::gc_animal},
{NULL, NULL}
};
const luaL_reg LuaAnimal::methods_f[] = {
{"creat", LuaAnimal::creat},
{NULL, NULL}
};
int main()
{
lua_State *L = luaL_newstate();
luaL_openlibs(L);
//
LuaAnimal::Register(L);
if (luaL_loadfile(L, "chenee.lua") || lua_pcall(L, 0, 0, 0)){
cout << "cannot run config. file:" << lua_tostring(L,-1) << endl;
}
lua_close(L);
return 0;
}