RPG游戏制作-08-为lua注册c/c++函数
接下来,就可以注册c函数给lua使用了。本游戏中把不同种类的函数集合成各种各样的模块,就类似于lua中的math模块io模块。目前的模块如下:
1.base模块,注册了一些常用的基础函数。
2.movement模块,移动函数,场景切换函数等。
3.screen模块,场景相关函数,如淡入淡出函数,调出背包函数等。
4.timer模块,延迟函数。
void register_funcs(lua_State* pL)
{static const luaL_Reg cpplibs[] = {{"base", open_base},{"movement", open_movement},{"screen", open_screen},{"timer", open_timer},{NULL, NULL}};const luaL_Reg* lib = nullptr;for (lib = cpplibs;lib->func;lib++){luaL_requiref(pL, lib->name, lib->func, 1);lua_pop(pL, 1);}
}
这个函数类似于lua中的luaL_openlibs(),添加了全部的模块。详细的请看帖子:
https://blog.csdn.net/bull521/article/details/79938211
然后就是一些模块内函数的编写,由于目前函数较少,故全部放在了ScriptFunc.h ScriptFunc.cpp文件中。
//------------------------------base------------------------------------
//一些基础的函数及声明
extern int open_base(lua_State* pL);
//游戏状态
extern int getGameState(lua_State* pL);
extern int setGameState(lua_State* pL);
每个模块都必有一个open_*()函数,来注册相关的函数给lua。
int open_base(lua_State* pL)
{const luaL_Reg baselib[] = {{"getGameState", getGameState},{"setGameState", setGameState},{NULL, NULL}};luaL_newlib(pL, baselib);return 1;
}
int getGameState(lua_State* pL)
{auto state = GameScene::getInstance()->getGameState();lua_Integer nState = static_cast(state);lua_pushinteger(pL, nState);return 1;
}int setGameState(lua_State* pL)
{lua_Integer nState = luaL_checkinteger(pL, 1);GameState state = static_cast(nState);GameScene::getInstance()->setGameState(state);return 0;
}
游戏状态主要是了以后在进行脚本状态下,需要屏蔽各种事件的响应。
在lua中使用c/c++中的枚举体有两种方法:
1.在c/c++中创建一个table,之后放入对应的键值对,如果有多个,重复上述操作。
2.在lua中根据枚举体的值直接创建。
我这里使用的是第二种,第一种虽然能实现当枚举体的顺序改变时,不需要修改枚举体注册函数,但是当枚举体太多时,会有很多重复性代码。
//------------------------------movement------------------------------------
int open_movement(lua_State* pL)
{const luaL_Reg movementlib[] = {{"changeMap", changeMap},{NULL, NULL}};luaL_newlib(pL, movementlib);return 1;
}int changeMap(lua_State* pL)
{const char* mapName = luaL_checkstring(pL, 1);float x = (float)luaL_checknumber(pL, 2);float y = (float)luaL_checknumber(pL, 3);GameScene::getInstance()->changeMap(mapName, Point(x, y));return 0;
}
movement模块中目前仅有一个切换地图函数。
//------------------------------screen------------------------------------
int open_screen(lua_State* pL)
{const luaL_Reg screenlib[] = {{"fadeInScreen", fadeInScreen},{"fadeOutScreen", fadeOutScreen},{NULL, NULL}};luaL_newlib(pL, screenlib);return 1;
}int fadeInScreen(lua_State* pL)
{float duration = (float)luaL_checknumber(pL, 1);auto gameScene = GameScene::getInstance();auto scriptLayer = gameScene->getScriptLayer();//设置等待时间scriptLayer->setWaitType(WaitType::Time);scriptLayer->setWaitTime(duration);gameScene->getEffectLayer()->fadeInScreen(duration);gameScene->yield(0);return 0;
}int fadeOutScreen(lua_State* pL)
{float duration = (float)luaL_checknumber(pL, 1);auto gameScene = GameScene::getInstance();auto scriptLayer = gameScene->getScriptLayer();//设置等待时间scriptLayer->setWaitType(WaitType::Time);scriptLayer->setWaitTime(duration);gameScene->getEffectLayer()->fadeOutScreen(duration);gameScene->yield(0);return 0;
}
淡入淡出场景函数会阻塞对应脚本的执行,即协程,这里注意下yield的位置是在函数的末尾的,因为lua_yield()后的语句不会执行的,这个在lua wiki中有说明。
//------------------------------screen------------------------------------
int open_timer(lua_State* pL)
{const luaL_Reg timerlib[] = {{"delay", delay},{NULL, NULL}};luaL_newlib(pL, timerlib);return 1;
}int delay(lua_State* pL)
{float duration = (float)luaL_checknumber(pL, 1);auto gameScene = GameScene::getInstance();auto scriptLayer = gameScene->getScriptLayer();//设置等待时间scriptLayer->setWaitType(WaitType::Time);scriptLayer->setWaitTime(duration);gameScene->yield(0);return 0;
}
代码同上,相比于淡入淡出场景只是少了一个动画而已。
int GameScene::yield(int nresult)
{return lua_yield(m_pLuaState, nresult);
}
简单封装了lua_yield()。其实可以直接在上面的函数中lua_yield(pL)的,因为pL就是GameScene中的m_pLuaState,这里是为了保持一致性,故全部调用的GameScene中封装的函数。
另外一个问题就是注意一下NPC的execute函数的修改:
bool NonPlayerCharacter::execute(int playerID)
{auto gameScene = GameScene::getInstance();int result = LUA_ERRRUN;bool ret = false;//获得函数gameScene->getLuaGlobal(m_name.c_str());gameScene->getLuaField(-1, "execute");//放入参数gameScene->getLuaGlobal(m_name.c_str());gameScene->pushInt(playerID);//执行函数result = gameScene->resumeFunction(2);if (result == LUA_YIELD){}else if (result == LUA_OK){//获取返回值ret = gameScene->toLuaBoolean(-1);gameScene->pop(2);}int n = lua_gettop(gameScene->getLuaState());return ret;
}
当lua_resume()返回的是LUA_YIELD时,此时的栈会被清空,也就是说不需要主动清空栈即可,而返回LUA_OK时,则需要主动清空栈的内容。
然后就是在lua文件中添加内容了。
先创建一个rpg_core.lua,内部声明了一些table来映射c/c++中的枚举体。
--包含着一些枚举体和一些函数
--游戏状态枚举体
GameState = {};
GameState.Normal = 0;
GameState.Fighting = 1;
GameState.Script = 2;
然后就是 "门"table:
--传送门 传送到1.tmx
Map01_02_Portal01 = NonPlayerCharacter:new();function Map01_02_Portal01:execute(playerID)base.setGameState(GameState.Script);--淡入场景screen.fadeInScreen(0.8);--切换场景movement.changeMap("map/1.tmx",26,23);--淡出场景screen.fadeOutScreen(0.8);base.setGameState(GameState.Normal);return true;
end
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
