//
// fun.h
// LuaWithCpp
//
// Created by zctech on 14-3-3.
//
//
#ifndef __LuaWithCpp__fun__
#define __LuaWithCpp__fun__
#include <iostream>
class Foo
{
public:
Foo(const std::string & name) : name(name)
{
std::cout << "Foo is born" << std::endl;
}
std::string Add(int a, int b)
{
std::stringstream ss;
ss << name << ": " << a << " + " << b << " = " << (a+b);
return ss.str();
}
~Foo()
{
std::cout << "Foo is gone" << std::endl;
}
private:
std::string name;
};
int l_Foo_constructor(lua_State * l);
Foo * l_CheckFoo(lua_State * l, int n);
int l_Foo_add(lua_State * l);
int l_Foo_destructor(lua_State * l);
void RegisterFoo(lua_State * l);
#endif /* defined(__LuaWithCpp__fun__) */
//
// fun.cpp
// Language_Lua
//
// Created by 郭 一鸣 on 14-1-18.
//
//
extern "C"
{
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
}
#include <iostream>
#include <sstream>
#include "fun.h"
// The general pattern to binding C++ class to Lua is to write a Lua
// thunk for every method for the class, so here we go:
int l_Foo_constructor(lua_State * l)
{
const char * name = luaL_checkstring(l, 1);
// We could actually allocate Foo itself as a user data but
// since user data can be GC'ed and we gain unity by using CRT's heap
// all along.
Foo ** udata = (Foo **)lua_newuserdata(l, sizeof(Foo *));
*udata = new Foo(name);
// Usually, we'll just use "Foo" as the second parameter, but I
// say luaL_Foo here to distinguish the difference:
//
// This 2nd parameter here is an _internal label_ for luaL, it is
// _not_ exposed to Lua by default.
//
// Effectively, this metatable is not accessible by Lua by default.
luaL_getmetatable(l, "luaL_Foo");
// The Lua stack at this point looks like this:
//
// 3| metatable "luaL_foo" |-1
// 2| userdata |-2
// 1| string parameter |-3
//
// So the following line sets the metatable for the user data to the luaL_Foo
// metatable
//
// We must set the metatable here because Lua prohibits setting
// the metatable of a userdata in Lua. The only way to set a metatable
// of a userdata is to do it in C.
lua_setmetatable(l, -2);
// The Lua stack at this point looks like this:
//
// 2| userdata |-1
// 1| string parameter |-2
//
// We return 1 so Lua callsite will get the user data and
// Lua will clean the stack after that.
return 1;
}
Foo * l_CheckFoo(lua_State * l, int n)
{
// This checks that the argument is a userdata
// with the metatable "luaL_Foo"
return *(Foo **)luaL_checkudata(l, n, "luaL_Foo");
}
int l_Foo_add(lua_State * l)
{
Foo * foo = l_CheckFoo(l, 1);
int a = luaL_checknumber(l, 2);
int b = luaL_checknumber(l, 3);
std::string s = foo->Add(a, b);
lua_pushstring(l, s.c_str());
// The Lua stack at this point looks like this:
//
// 4| result string |-1
// 3| metatable "luaL_foo" |-2
// 2| userdata |-3
// 1| string parameter |-4
//
// Return 1 to return the result string to Lua callsite.
return 1;
}
int l_Foo_destructor(lua_State * l)
{
Foo * foo = l_CheckFoo(l, 1);
delete foo;
return 0;
}
void RegisterFoo(lua_State * l)
{
luaL_Reg sFooRegs[] =
{
{ "new", l_Foo_constructor },
{ "add", l_Foo_add },
{ "__gc", l_Foo_destructor },
{ NULL, NULL }
};
// Create a luaL metatable. This metatable is not
// exposed to Lua. The "luaL_Foo" label is used by luaL
// internally to identity things.
luaL_newmetatable(l, "luaL_Foo");
// Register the C functions _into_ the metatable we just created.
luaL_register(l, NULL, sFooRegs);
// The Lua stack at this point looks like this:
//
// 1| metatable "luaL_Foo" |-1
lua_pushvalue(l, -1);
// The Lua stack at this point looks like this:
//
// 2| metatable "luaL_Foo" |-1
// 1| metatable "luaL_Foo" |-2
// Set the "__index" field of the metatable to point to itself
// This pops the stack
lua_setfield(l, -1, "__index");
// The Lua stack at this point looks like this:
//
// 1| metatable "luaL_Foo" |-1
// The luaL_Foo metatable now has the following fields
// - __gc
// - __index
// - add
// - new
// Now we use setglobal to officially expose the luaL_Foo metatable
// to Lua. And we use the name "Foo".
//
// This allows Lua scripts to _override_ the metatable of Foo.
// For high security code this may not be called for but
// we'll do this to get greater flexibility.
lua_setglobal(l, "Foo");
}
#include "cocos2d.h"
#include "CCEGLView.h"
#include "AppDelegate.h"
#include "CCLuaEngine.h"
#include "SimpleAudioEngine.h"
#include "Lua_extensions_CCB.h"
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS || CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID || CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)
#include "Lua_web_socket.h"
#endif
#include "TestScene.h"
#include "fun.h"
using namespace CocosDenshion;
USING_NS_CC;
AppDelegate::AppDelegate()
{
}
AppDelegate::~AppDelegate()
{
SimpleAudioEngine::end();
}
bool AppDelegate::applicationDidFinishLaunching()
{
// initialize director
CCDirector *pDirector = CCDirector::sharedDirector();
pDirector->setOpenGLView(CCEGLView::sharedOpenGLView());
// turn on display FPS
pDirector->setDisplayStats(true);
// set FPS. the default value is 1.0/60 if you don't call this
pDirector->setAnimationInterval(1.0 / 60);
// register lua engine
CCLuaEngine* pEngine = CCLuaEngine::defaultEngine();
CCScriptEngineManager::sharedManager()->setScriptEngine(pEngine);
CCLuaStack *pStack = pEngine->getLuaStack();
lua_State *tolua_s = pStack->getLuaState();
tolua_extensions_ccb_open(tolua_s);
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS || CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID || CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)
pStack = pEngine->getLuaStack();
tolua_s = pStack->getLuaState();
tolua_web_socket_open(tolua_s);
#endif
#if (CC_TARGET_PLATFORM == CC_PLATFORM_BLACKBERRY)
CCFileUtils::sharedFileUtils()->addSearchPath("script");
#endif
std::string path = CCFileUtils::sharedFileUtils()->fullPathForFilename("hello.lua");
// pEngine->executeScriptFile(path.c_str());
CCFileUtils::sharedFileUtils()->addSearchPath("lua");
//pDirector->runWithScene(TestScene::scene());
// register binding class
RegisterFoo(pEngine->getLuaStack()->getLuaState());
path = CCFileUtils::sharedFileUtils()->fullPathForFilename("fun.lua");
pEngine->executeScriptFile(path.c_str());
return true;
}
// This function will be called when the app is inactive. When comes a phone call,it's be invoked too
void AppDelegate::applicationDidEnterBackground()
{
CCDirector::sharedDirector()->stopAnimation();
SimpleAudioEngine::sharedEngine()->pauseBackgroundMusic();
}
// this function will be called when the app is active again
void AppDelegate::applicationWillEnterForeground()
{
CCDirector::sharedDirector()->startAnimation();
SimpleAudioEngine::sharedEngine()->resumeBackgroundMusic();
}
-- fun.lua
-- Because the metatable has been exposed
-- to us, we can actually add new functions
-- to Foo
function Foo:speak()
print("Hello, I am a Foo")
end
local foo = Foo.new("fred")
local m = foo:add(3, 4)
-- "fred: 3 + 4 = 7"
print(m)
-- "Hello, I am a Foo"
foo:speak()
-- Let's rig the original metatable
Foo.add_ = Foo.add
function Foo:add(a, b)
return "here comes the magic: " .. self:add_(a, b)
end
m = foo:add(9, 8)
-- "here comes the magic: fred: 9 + 8 = 17"
print(m)