lua腳本在游戲中的應用


一,為什么要在游戲中使用腳本語言?

  要解釋這個問題首先我們先來了解一下腳本語言的特性:

  1,學習門檻低,快速上手。

  2,開發成本低,可維護性強。

  3,動態語言,靈活性高。

  相對於C/C++這類高復雜性、高風險的編譯型語言來說,Lua腳本做為一種輕量級的動態語言,簡單的語言特性,精簡的核心和基礎庫,使得語言的學習門檻大大的降低,即使是沒有任何游戲經驗的人都能快速上手,開發游戲功能。實際上游戲設計是一種十分繁雜的工作,C/C++雖然給我們帶來極大的高效性,但同時也不能忽視其復雜性,極易產生BUG,而且對於開發人員的要求非常高。從語言的的抽象層面來說C/C++的抽象低更加適合於底層邏輯的支持,而Lua腳本抽象層次高,更加適合游戲邏輯的實現。腳本語言運行在虛擬機之上,而虛擬機運行在游戲邏輯之上,作為一種解釋型語言,我們可以隨時修改並及時體現在游戲之中,快速完成開發。C/C++卻做不到,對一個巨大的游戲工程,每次修改都需要重新編譯,成本很高。設想一下,如果所有的功能都是使用C/C++實現的話,那么對開發人員來說簡直是一場災難。

  二,如何在游戲中使用Lua腳本?

  這里就不理論一大堆了,直接手把手教。

  1,進入Lua官方網站下載Source源代碼

  2,在Visual Studio在新建一個解決方案名為Lua2Game

  3,在Lua2Game解決方案下新建一個空項目,命名為LuaDll,將從Lua官網下載的源代碼src中除luac.c文件之外的源代碼拷貝到LuaDll工程,配置項目屬性,常規->配置類型為靜態庫(lib)然后編譯LuaDll項目。(luac.c是編譯器,lua.c是解釋器也就是lua虛擬機)

  4,在Lua2Game解決方案下新建一個空項目,命名為Game,配置項目屬性,常規->配置類型為應用程序(.exe), 這就是游戲demo。在項目屬性中,鏈接器-> 輸入->附加依賴項中加入../Debug/LuaDll.lib

  5,在項目Game中實現腳本引擎CLuaScript(實現C/C++與Lua腳本的互相訪問)

  LuaScript.h

  #ifndef LUA_SCRIPT_H

  #define LUA_SCRIPT_H

  #include "GameDef.h"

  class CLuaScript

  {

  public:

  CLuaScript();

  ~CLuaScript();

  public:

  //實現C/C++對Lua腳本的調用

  bool LoadScript(const char* szFileName); //實現lua腳本加載和編譯

  //調用Lua函數

  bool CallFunction(char cFuncName, int nResults, char cFormat, va_list vlist);

  bool CallFunction(const char cFuncName, int nResults, char cFormat, ...);

  private:

  void RegisterLuaLib(); //注冊lua各種基礎庫

  bool RegisterFunctions(TLua_Funcs Funcs[], int n);//將游戲接口注冊到lua腳本

  private:

  lua_State* m_LuaState; //state 腳本和C\C++搞基就靠它了

  bool m_IsLoadScript;

  };

  #endif

  LuaScript.cpp

  #include

  #include "LuaScript.h"

  CLuaScript::CLuaScript()

  {

  m_LuaState = luaL_newstate();

  if (!m_LuaState)

  {

  std::cout << "m_LuaState new state failed!" << std::endl;

  return;

  }

  RegisterLuaLib();//注冊lua標准庫

  RegisterFunctions(g_GameFunc, g_GetGameFuncSize());//注冊c\c++腳本接口

  m_IsLoadScript = false;

  }

  CLuaScript::~CLuaScript()

  {

  if (m_LuaState)

  {

  lua_close(m_LuaState);

  m_LuaState = NULL;

  }

  m_IsLoadScript = false;

  }

  void CLuaScript::RegisterLuaLib()

  {

  if (!m_LuaState)

  {

  return;

  }

  luaL_openlibs(m_LuaState);

  }

  bool CLuaScript::RegisterFunctions(TLua_Funcs Funcs[], int n)

  {

  if (!m_LuaState)

  {

  return false;

  }

  for (int i = 0; i < n; i++)

  lua_register(m_LuaState, Funcs[i].name, Funcs[i].func);

  return true;

  }

  bool CLuaScript::LoadScript(const char* szFileName)

  {

  if (!szFileName || szFileName[0] == '\0')

  {

  std::cout << "Lua script file illegal!" << std::endl;

  return false;

  }

  if (!m_LuaState)

  return false;

  m_IsLoadScript = (www.cungun.comluaL_dofile(m_LuaState, szFileName) == LUA_OK);

  if (!m_IsLoadScript)

  {

  std::cout << ""<< lua_tostring(m_LuaState, -1) << std::endl;

  lua_pop(m_LuaState, 1);

  }

  return m_IsLoadScript;

  }

  bool CLuaScript::CallFunction(char cFuncName, int nResults, char cFormat, va_list vlist)

  {

  if (!m_LuaState || !m_IsLoadScript)

  return false;

  double nNumber = 0;

  int nInteger = 0;

  char* cString = NULL;

  void* pPoint = NULL;

  int i = 0;

  int nArgnum = 0;

  lua_CFunction CFunc = NULL;

  lua_getglobal(m_LuaState, cFuncName); //在堆棧中加入需要調用的函數名

  while (cFormat[i] != '\0')

  {

  switch (cFormat[i])

  {

  case 'n'://輸入的數據是double形 NUMBER,Lua來說是Double型

  {

  nNumber = va_arg(vlist, double);

  lua_pushnumber(m_LuaState, nNumber);

  nArgnum++;

  }

  break;

  case 'd'://輸入的數據為整形

  {

  nInteger = va_arg(vlist, int);

  lua_pushinteger(m_LuaState, nInteger);

  nArgnum++;

  }

  break;

  case 's'://字符串型

  {

  cString = va_arg(vlist, char *);

  lua_pushstring(m_LuaState, cString);

  nArgnum++;

  }

  break;

  case 'N'://NULL

  {

  lua_pushnil(m_LuaState);

  nArgnum++;

  }

  break;

  case 'f'://輸入的是CFun形,即內部函數形

  {

  CFunc = va_arg(vlist, lua_CFunction);

  lua_pushcfunction(m_LuaState, CFunc);

  nArgnum++;

  }

  break;

  case 'v'://輸入的是堆棧中Index為nIndex的數據類型

  {

  nNumber = va_arg(vlist, int);

  int nIndex1 = (int)nNumber;

  lua_pushvalue(m_LuaState, nIndex1);

  nArgnum++;

  }

  break;

  }

  i++;

  }

  int nRetcode = lua_pcall(m_LuaState, nArgnum, nResults, 0);

  if (nRetcode != 0)

  {

  std::cout << "" << lua_tostring(m_LuaState, -1) << std::endl;

  lua_pop(m_LuaState, 1);

  return false;

  }

  return true;

  }

  bool CLuaScript::CallFunction(const char cFuncName, int nResults, char cFormat, ...)

  {

  bool bResult = false;

  va_list vlist;

  va_start(vlist, cFormat);

  bResult = CallFunction((char*)cFuncName, nResults, cFormat, vlist);

  va_end(vlist);

  return bResult;

  }

  6,定義用於實現定義給lua腳本的游戲接口

  GameDef.h

  #ifndef GAME_DEF_H

  #define GAME_DEF_H

  extern "C"{

  #include "../../LuaDll/src/lua.h"

  #include "../../LuaDll/src/lauxlib.h"

  #include "../../LuaDll/src/lualib.h"

  }

  struct TLua_Funcs

  {

  const char *name;

  lua_CFunction func;

  };

  extern TLua_Funcs g_GameFunc[];

  extern int g_GetGameFuncSize();

  #endif

  GameDef.cpp

  #include "GameDef.h"

  #include

  #include

  #include "Core.h"

  using namespace std;

  int LuaSayHello(lua_State* L)

  {

  cout << "Lua call c/c++:SayHello()" << endl;

  cout << "Hello Everyone!" << endl;

  if (lua_gettop(L) < 3)

  return 0;

  const char* szName = lua_tostring(L, 1);

  int nParam1 = lua_tonumber(L, 2);

  int nParam2 = lua_tonumber(L, 3);

  cout << "My name is " << szName << endl;

  lua_pushnumber(L, nParam1 / nParam2);

  return 1;

  }

  int LuaStopGame(lua_State* L)

  {

  cout << "Lua call c/c++:StopGame()" << endl;

  cout << "Game is over!" << endl;

  g_Core.SetRunState(false);

  return 0;

  }

  //腳本接口

  TLua_Funcs g_GameFunc[] = {

  { "SayHello", LuaSayHello },

  { "StopGame", LuaStopGame },

  };

  int g_GetGameFuncSize()

  {

  return sizeof(g_GameFunc) / sizeof(TLua_Funcs);

  }

  7,模擬游戲主邏輯

  Core.h

  #ifndef CORE_H

  #define CORE_H

  #include "GameDef.h"

  #include "LuaScript.h"鄭州婦科醫院排名http:/w.tongjink.com/

  class CCore

  {

  public:

  CCore();

  ~CCore();

  public:

  bool Initialize();

  void Uninitialize();

  bool Breathe();

  void SetRunState(bool bRunning);

  private:

  CLuaScript* m_Script;

  bool m_bIsRuning;

  };

  extern CCore g_Core;

  #endif


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM