在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
以前写过一篇Lua的基础文章,属于基础的技术普及贴,具体请参阅精华区。以下的文章,希望你能稍微了解一些Lua的基础知识,再来阅读更有益处。 #include <string> #include <map> using namespace std; class CPlayer { public: CPlayer(void) {}; ~CPlayer(void) {}; //创建一个玩家信息 void CreatePlayer(int nPlayerID, string strPlayerName) { m_nPlayerID = nPlayerID; //玩家的ID m_nMessionID = 0; //玩家的任务 m_nItemID = 0; //玩家所持有的物品ID m_strPlayerName = strPlayerName; //玩家的昵称 m_strMessionDesc = ""; //任务的描述 }; int GetPlayerID() { return m_nPlayerID; }; bool SetMessionID(int nMessionID) { if(m_nMessionID != 0) { return false; } m_nMessionID = nMessionID; return true; }; int GetMessionID() { return m_nMessionID; } void FinishMessionID() { m_nMessionID = 0; }; void SetMessionDesc(const char* pDesc) { m_strMessionDesc = pDesc; }; void SetItemID(int nItemID) { m_nItemID = nItemID; }; int GetItemID() { return m_nItemID; } private: int m_nPlayerID; //玩家ID string m_strPlayerName; //玩家姓名 int m_nMessionID; //玩家任务ID string m_strMessionDesc; //玩家任务描述 int m_nItemID; //玩家所持物品ID }; class CPlayerManager { private: CPlayerManager() {}; public: static CPlayerManager& Instance() { if(m_pPlayerManager == NULL) { m_pPlayerManager = new CPlayerManager(); } return *m_pPlayerManager; }; ~CPlayerManager() { Close(); }; bool AddPlayer(CPlayer* pPlayer) { if(NULL == pPlayer) { return false; } mapPlayerManager::iterator f = m_mapPlayerManager.find(pPlayer->GetPlayerID()); if(f != m_mapPlayerManager.end()) { return false; } m_mapPlayerManager.insert(mapPlayerManager::value_type(pPlayer->GetPlayerID(), pPlayer)); return true; }; CPlayer* GetPlayer(int nPlayerID) { mapPlayerManager::iterator f = m_mapPlayerManager.find(nPlayerID); if(f != m_mapPlayerManager.end()) { return (CPlayer* )f->second; } else { return NULL; } }; void Close() { mapPlayerManager::iterator b = m_mapPlayerManager.begin(); mapPlayerManager::iterator e = m_mapPlayerManager.end(); for(b; b != e; b++) { CPlayer* pPlayer = (CPlayer* )b->second; if(NULL == pPlayer) { delete pPlayer; pPlayer = NULL; } } }; private: typedef map<int, CPlayer*> mapPlayerManager; mapPlayerManager m_mapPlayerManager; static CPlayerManager* m_pPlayerManager; };
呵呵,这个类很简单,里面包含了一些玩家的基本信息,并提供了一个CPlayerManager()的管理类,管理所有已经注册的CPlayer对象,这些CPlayer对象提供给我了修改玩家种种属性的方法。
#ifndef LUAFNREGISTER_H #define LUAFNREGISTER_H //lua下的C++注册类,负责处理lua中用到的C++函数 //add by freeeyes #include "LuaDefine.h" #include <vector> #include <string> using namespace std; typedef int (*FuncExecute)(lua_State* plua_State); struct _FuncInfo { string m_strFuncName; FuncExecute m_FuncExecute; }; //这个类负责管理所有注册的lua对C++函数类 class CLuaFnRegister { public: CLuaFnRegister() {}; ~CLuaFnRegister() {}; void Close() { m_vecLuaFnRegCollection.clear(); }; bool AddFunc(const char* pFuncName, FuncExecute pFn) { _FuncInfo objFuncInfo; objFuncInfo.m_strFuncName = pFuncName; objFuncInfo.m_FuncExecute = pFn; m_vecLuaFnRegCollection.push_back(objFuncInfo); return true; }; int GetSize() { return (int)m_vecLuaFnRegCollection.size(); }; _FuncInfo* GetFuncInfo(int nIndex) { if(nIndex >= (int)m_vecLuaFnRegCollection.size()) { return NULL; } else { return (_FuncInfo* )&m_vecLuaFnRegCollection[nIndex]; } }; private: typedef vector<_FuncInfo> vecLuaFnRegCollection; vecLuaFnRegCollection m_vecLuaFnRegCollection; }; #endif
首先,我用一个类,来管理所有我的修改方法在lua中的注册。一个函数名外加一个函数指针,就完成了一个注册。这个类用于管理所有已知我需要让lua调用我的方法。
#ifndef _LUAFN_MESSION_H #define _LUAFN_MESSION_H #include "LuaDefine.h" #include "Player.h" //执行远程函数 static int LuaExecute_Func(lua_State* pState, const char* pFuncName, int nPlayerID) { lua_getglobal(pState, pFuncName); lua_pushnumber(pState, nPlayerID); int nRet = lua_pcall(pState, 1, 0, 0); if (nRet != 0) { printf("[LuaExecute_Func]call function(%s) error(%s).\n", pFuncName, lua_tostring(pState, -1)); return false; } lua_settop(pState, -1); return 0; } //输出文字 static int LuaFn_Mession_Print(lua_State* pState) { char* pGlobal = (char* )lua_tostring(pState, -1); printf_s("[LuaFn_Mession_Print]Data=%s.\n", pGlobal); return 0; } //输入描述信息 static int Lua_Mession_Desc(lua_State* pState) { int nPlayerID = (int)lua_tonumber(pState, -2); char* pDesc = (char* )lua_tostring(pState, -1); //printf_s("[Lua_Mession_Desc]nPlayerID=%d, pDesc=%s.\n", nPlayerID, pDesc); CPlayer* pPlayer = CPlayerManager::Instance().GetPlayer(nPlayerID); if(NULL == pPlayer) { lua_pushboolean(pState, (int)false); } else { pPlayer->SetMessionDesc(pDesc); lua_pushboolean(pState, (int)true); } return 1; } //输入描述信息 static int Lua_Mession_Error(lua_State* pState) { int nPlayerID = (int)lua_tonumber(pState, -2); char* pDesc = (char* )lua_tostring(pState, -1); CPlayer* pPlayer = CPlayerManager::Instance().GetPlayer(nPlayerID); if(NULL == pPlayer) { lua_pushboolean(pState, (int)false); } else { pPlayer->SetMessionDesc(pDesc); lua_pushboolean(pState, (int)true); } return 1; } //当前用户是否存在任务,如果有则返回False static int Lua_Mession_IsHave(lua_State* pState) { int nPlayerID = (int)lua_tonumber(pState, -1); CPlayer* pPlayer = CPlayerManager::Instance().GetPlayer(nPlayerID); if(NULL == pPlayer) { lua_pushboolean(pState, (int)false); } else { if(pPlayer->GetMessionID() != 0) { lua_pushboolean(pState, (int)true); } else { lua_pushboolean(pState, (int)false); } } return 1; } //得到用户任务ID static int Lua_Mession_GetID(lua_State* pState) { int nPlayerID = (int)lua_tonumber(pState, -1); CPlayer* pPlayer = CPlayerManager::Instance().GetPlayer(nPlayerID); if(NULL == pPlayer) { lua_pushnumber(pState, 0); } else { int nMessionID = pPlayer->GetMessionID(); lua_pushnumber(pState, nMessionID); } return 1; } //得到用户任务ID static int Lua_Mession_SetID(lua_State* pState) { int nPlayerID = (int)lua_tonumber(pState, -2); int nMessionID = (int)lua_tonumber(pState, -1); CPlayer* pPlayer = CPlayerManager::Instance().GetPlayer(nPlayerID); if(NULL != pPlayer) { pPlayer->SetMessionID(nMessionID); } return 0; } //给与玩家道具ID static int Lua_Mession_SetItemID(lua_State* pState) { int nPlayerID = (int)lua_tonumber(pState, -3); int nMessionID = (int)lua_tonumber(pState, -2); int nItemID = (int)lua_tonumber(pState, -1); CPlayer* pPlayer = CPlayerManager::Instance().GetPlayer(nPlayerID); if(NULL != pPlayer) { pPlayer->SetItemID(nItemID); } return 0; } //得到玩家道具ID static int Lua_Mession_GetItemID(lua_State* pState) { int nPlayerID = (int)lua_tonumber(pState, -2); int nMessionID = (int)lua_tonumber(pState, -1); CPlayer* pPlayer = CPlayerManager::Instance().GetPlayer(nPlayerID); if(NULL != pPlayer) { int nItemID = pPlayer->GetItemID(); lua_pushnumber(pState, nItemID); } else { lua_pushnumber(pState, 0); } return 1; } //完成任务 static int Lua_Mession_Done(lua_State* pState) { int nPlayerID = (int)lua_tonumber(pState, -2); int nMessionID = (int)lua_tonumber(pState, -1); CPlayer* pPlayer = CPlayerManager::Instance().GetPlayer(nPlayerID); if(NULL != pPlayer) { pPlayer->FinishMessionID(); } return 0; } //调用远程事件处理函数 static int Lua_Mession_Events(lua_State* pState) { int nPlayerID = (int)lua_tonumber(pState, -2); int nMessionID = (int)lua_tonumber(pState, -1); //lua_pop(pState, -1); //调用远程接口 char szFuncName[100] = {'\0'}; sprintf(szFuncName, "Event_%d_Request", nMessionID); LuaExecute_Func(pState, szFuncName, nPlayerID); return 0; } #endif
好了,我提供了一批方法给策划,这就是作料,如果策划觉得不够,我可以随意添加。这里你可以看到,我所有传给lua的方法,都是以基础类型为参数的,避免了设计中的类传递,这也是我抵触把类给Lua的实现,因为在实现细节上,任何修改都应该可以转变成对基础类型的修改。所以,你没有必要把类给策划,让他自己去找繁复的接口。你给他们的,都是清晰可见的,而且是独立的。这样,减少了策划误用错用你的接口的可能性。
bool CLuaFn::InitClass() { if(NULL == m_pState) { printf("[CLuaFn::InitClass]m_pState is NULL.\n"); return false; } tolua_open(m_pState); tolua_module(m_pState, NULL, 0); tolua_beginmodule(m_pState, NULL); m_LuaFnRegister.AddFunc("LuaFn_Mession_Print", LuaFn_Mession_Print); m_LuaFnRegister.AddFunc("Lua_Mession_Error", Lua_Mession_Error); m_LuaFnRegister.AddFunc("Lua_Mession_Desc", Lua_Mession_Desc); m_LuaFnRegister.AddFunc("Lua_Mession_IsHave", Lua_Mession_IsHave); m_LuaFnRegister.AddFunc("Lua_Mession_GetID", Lua_Mession_GetID); m_LuaFnRegister.AddFunc("Lua_Mession_SetID", Lua_Mession_SetID); m_LuaFnRegister.AddFunc("Lua_Mession_SetItemID", Lua_Mession_SetItemID); m_LuaFnRegister.AddFunc("Lua_Mession_GetItemID", Lua_Mession_GetItemID); m_LuaFnRegister.AddFunc("Lua_Mession_Done", Lua_Mession_Done); m_LuaFnRegister.AddFunc("Lua_Mession_Events", Lua_Mession_Events); for(int i = 0; i < m_LuaFnRegister.GetSize(); i++) { _FuncInfo* pFuncInfo = m_LuaFnRegister.GetFuncInfo(i); if(NULL != pFuncInfo) { tolua_function(m_pState, pFuncInfo->m_strFuncName.c_str(), pFuncInfo->m_FuncExecute); } } tolua_endmodule(m_pState); return true; }
呵呵,看到了吧,一点也不复杂。
--NPC的ID,在程序里面对应NPC NPC_1001_NAME="自由之眼" function NPC_1001_OnDefault(nMapID, nPlayerID) blMessionState = Lua_Mession_IsHave(nPlayerID) if blMessionState == true then --如果任务有,则判断是否需要完成 nMessionID = Lua_Mession_GetID(nMapID, nPlayerID) NPC_1001_OnSubmit(nMapID, nPlayerID, nMessionID) else Lua_Mession_SetID(nPlayerID, 200001) Lua_Mession_Desc(nPlayerID, "请选择你要接受的任务信息,1是要土豆,2是要黄铜。") end end function NPC_1001_OnEvents(nMapID, nPlayerID) nMessionID = Lua_Mession_GetID(nMapID, nPlayerID) --print("[NPC_1001_OnEvents]nMessionID="..nMessionID) if nMessionID ~= 0 then Lua_Mession_Events(nPlayerID, nMessionID) end end function NPC_1001_OnSubmit(nMapID, nPlayerID, nMessionID) nItemID = Lua_Mession_GetItemID(nPlayerID, nMessionID) if nMessionID == 200001 then if nItemID == 300 then Lua_Mession_Done(nPlayerID, nMessionID) --LuaFn_Mession_Print("200001 完成了。") end end if nMessionID == 200002 then if nItemID == 301 then Lua_Mession_Done(nPlayerID, nMessionID) --LuaFn_Mession_Print("200002 完成了。") end end end 呵呵,看看,我把自己做成了一个NPC,当然,如果你愿意,你可以建立无数个这样的NPC在这个游戏中。这里面提供了两个最简单的方法,当玩家碰触这个NPC,我们调用NPC_1001_OnDefault()方法,这里会验证玩家身上有没有任务,有,则会调用是否完成的函数。我准备了两个任务,200001和200002
function Event_200001_Request(nPlayerID) --LuaFn_Mession_Print("200001 给你一个土豆。") Lua_Mession_SetItemID(nPlayerID, 200001, 300) end function Event_200002_Request(nPlayerID) --LuaFn_Mession_Print("200002 给你一个黄铜。") Lua_Mession_SetItemID(nPlayerID, 200002, 301) end 我们姑且命名为Mession_Event_200001.lua(其实这个名字并不是很合适,呵呵,例子嘛)
|
请发表评论