zoukankan      html  css  js  c++  java
  • 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

     1 #ifndef __LUA_SCRIPT_H__
     2 #define __LUA_SCRIPT_H__
     3 
     4 #include "GameDef.h"
     5 
     6 class CLuaScript
     7 {
     8 public:
     9     CLuaScript();
    10     ~CLuaScript();
    11 
    12 public:
    13         //实现C/C++对Lua脚本的调用
    14     bool    LoadScript(const char* szFileName); //实现lua脚本加载和编译
    15     //调用Lua函数
    16     bool    CallFunction(char* cFuncName, int nResults, char* cFormat, va_list vlist);
    17     bool    CallFunction(const char* cFuncName, int nResults, char* cFormat, ...);
    18 
    19 private:
    20     void    RegisterLuaLib(); //注册lua各种基础库
    21     bool    RegisterFunctions(TLua_Funcs Funcs[], int n);//将游戏接口注册到lua脚本
    22     
    23 private:
    24     lua_State*    m_LuaState; //state 脚本和CC++搞基就靠它了
    25     bool        m_IsLoadScript;
    26 };
    27 
    28 
    29 #endif

    LuaScript.cpp

      1 #include <iostream>
      2 #include "LuaScript.h"
      3 
      4 CLuaScript::CLuaScript()
      5 {
      6     m_LuaState = luaL_newstate();
      7     if (!m_LuaState)
      8     {
      9         std::cout << "m_LuaState new state failed!" << std::endl;
     10         return;
     11     }
     12     RegisterLuaLib();//注册lua标准库
     13     RegisterFunctions(g_GameFunc, g_GetGameFuncSize());//注册cc++脚本接口
     14     m_IsLoadScript = false;
     15 }
     16 
     17 CLuaScript::~CLuaScript()
     18 {
     19     if (m_LuaState)
     20     {
     21         lua_close(m_LuaState);
     22         m_LuaState = NULL;
     23     }
     24     m_IsLoadScript = false;
     25 }
     26 
     27 void CLuaScript::RegisterLuaLib()
     28 {
     29     if (!m_LuaState)
     30     {
     31         return;
     32     }
     33     luaL_openlibs(m_LuaState);
     34 }
     35 
     36 bool CLuaScript::RegisterFunctions(TLua_Funcs Funcs[], int n)
     37 {
     38     if (!m_LuaState)
     39     {
     40         return false;
     41     }
     42     for (int i = 0; i < n; i++)
     43         lua_register(m_LuaState, Funcs[i].name, Funcs[i].func);
     44     return true;
     45 }
     46 
     47 bool CLuaScript::LoadScript(const char* szFileName)
     48 {
     49     if (!szFileName || szFileName[0] == '')
     50     {
     51         std::cout << "Lua script file illegal!" << std::endl;
     52         return false;
     53     }
     54     if (!m_LuaState)
     55         return false;
     56 
     57     m_IsLoadScript = (luaL_dofile(m_LuaState, szFileName) == LUA_OK);
     58     if (!m_IsLoadScript)
     59     {
     60         std::cout << "<LUA_LOAD_ERROR>"<< lua_tostring(m_LuaState, -1) << std::endl;
     61         lua_pop(m_LuaState, 1);
     62     }
     63     return m_IsLoadScript;
     64 }
     65 
     66 bool CLuaScript::CallFunction(char* cFuncName, int nResults, char* cFormat, va_list vlist)
     67 {
     68     if (!m_LuaState || !m_IsLoadScript)
     69         return false;
     70 
     71     double    nNumber    = 0;
     72     int nInteger    = 0;
     73     char*    cString    = NULL;
     74     void*    pPoint    = NULL;
     75     int i        = 0;
     76     int nArgnum    = 0;
     77     lua_CFunction CFunc = NULL;
     78 
     79     lua_getglobal(m_LuaState, cFuncName); //在堆栈中加入需要调用的函数名
     80 
     81     while (cFormat[i] != '')
     82     {
     83         switch (cFormat[i])
     84         {
     85         case 'n'://输入的数据是double形 NUMBER,Lua来说是Double型
     86         {
     87             nNumber = va_arg(vlist, double);
     88             lua_pushnumber(m_LuaState, nNumber);
     89             nArgnum++;
     90         }
     91         break;
     92 
     93         case 'd'://输入的数据为整形
     94         {
     95             nInteger = va_arg(vlist, int);
     96             lua_pushinteger(m_LuaState, nInteger);
     97             nArgnum++;
     98         }
     99         break;
    100 
    101         case 's'://字符串型
    102         {
    103             cString = va_arg(vlist, char *);
    104             lua_pushstring(m_LuaState, cString);
    105             nArgnum++;
    106         }
    107         break;
    108 
    109         case 'N'://NULL
    110         {
    111             lua_pushnil(m_LuaState);
    112             nArgnum++;
    113         }
    114         break;
    115 
    116         case 'f'://输入的是CFun形,即内部函数形
    117         {
    118             CFunc = va_arg(vlist, lua_CFunction);
    119             lua_pushcfunction(m_LuaState, CFunc);
    120             nArgnum++;
    121         }
    122         break;
    123 
    124         case 'v'://输入的是堆栈中Index为nIndex的数据类型
    125         {
    126             nNumber = va_arg(vlist, int);
    127             int nIndex1 = (int)nNumber;
    128             lua_pushvalue(m_LuaState, nIndex1);
    129             nArgnum++;
    130         }
    131         break;
    132         
    133         }
    134 
    135         i++;
    136     }
    137 
    138     int nRetcode = lua_pcall(m_LuaState, nArgnum, nResults, 0);
    139 
    140     if (nRetcode != 0)
    141     {
    142         std::cout << "<LUA_CALL_FUNC_ERROR>" << lua_tostring(m_LuaState, -1) << std::endl;
    143         lua_pop(m_LuaState, 1);
    144         return false;
    145     }
    146 
    147     return    true;
    148 }
    149 
    150 
    151 bool CLuaScript::CallFunction(const char* cFuncName, int nResults, char* cFormat, ...)
    152 {
    153     bool bResult = false;
    154     va_list vlist;
    155     va_start(vlist, cFormat);
    156     bResult = CallFunction((char*)cFuncName, nResults, cFormat, vlist);
    157     va_end(vlist);
    158     return bResult;
    159 }

    6,定义用于实现定义给lua脚本的游戏接口

    GameDef.h

     1 #ifndef __GAME_DEF_H__
     2 #define __GAME_DEF_H__
     3 
     4 extern "C"{
     5 #include "../../LuaDll/src/lua.h"
     6 #include "../../LuaDll/src/lauxlib.h"
     7 #include "../../LuaDll/src/lualib.h"
     8 }
     9 
    10 
    11 struct TLua_Funcs
    12 {
    13     const char *name;
    14     lua_CFunction func;
    15 };
    16 
    17 extern TLua_Funcs g_GameFunc[];
    18 extern int g_GetGameFuncSize();
    19 
    20 #endif

    GameDef.cpp

     1 #include "GameDef.h"
     2 #include <direct.h>
     3 #include <iostream>
     4 #include "Core.h"
     5 using namespace std;
     6 
     7 
     8 int LuaSayHello(lua_State* L)
     9 {
    10     cout << "Lua call c/c++:SayHello()" << endl;
    11     cout << "Hello Everyone!" << endl;
    12     if (lua_gettop(L) < 3)
    13         return 0;
    14     const char* szName = lua_tostring(L, 1);
    15     int nParam1 = lua_tonumber(L, 2);
    16     int nParam2 = lua_tonumber(L, 3);
    17     cout << "My name is " << szName << endl;
    18     lua_pushnumber(L, nParam1 / nParam2);
    19     return 1;
    20 }
    21 
    22 int LuaStopGame(lua_State* L)
    23 {
    24     cout << "Lua call c/c++:StopGame()" << endl;
    25     cout << "Game is over!" << endl;
    26     g_Core.SetRunState(false);
    27     return 0;
    28 }
    29 
    30 //脚本接口
    31 TLua_Funcs g_GameFunc[] = {
    32     { "SayHello", LuaSayHello },
    33     { "StopGame", LuaStopGame },
    34 };
    35 
    36 int g_GetGameFuncSize()
    37 {
    38     return sizeof(g_GameFunc) / sizeof(TLua_Funcs);
    39 }

    7,模拟游戏主逻辑

    Core.h

     1 #ifndef __CORE_H__
     2 #define __CORE_H__
     3 
     4 #include "GameDef.h"
     5 #include "LuaScript.h"
     6 
     7 class CCore
     8 {
     9 public:
    10     CCore();
    11     ~CCore();
    12 
    13 public:
    14     bool    Initialize();
    15     void    Uninitialize();
    16     bool    Breathe();
    17     void    SetRunState(bool bRunning);
    18 
    19 private:
    20     CLuaScript* m_Script;
    21     bool        m_bIsRuning;
    22 };
    23 
    24 extern CCore g_Core;
    25 
    26 #endif

    Core.cpp

     1 #include "Core.h"
     2 #include <time.h>
     3 #include <iostream>
     4 using namespace std;
     5 
     6 CCore g_Core;
     7 
     8 CCore::CCore()
     9 {
    10     m_Script = NULL;
    11     m_bIsRuning = true;
    12 }
    13 
    14 CCore::~CCore()
    15 {
    16     if (m_Script)
    17     {
    18         delete m_Script;
    19         m_Script = NULL;
    20     }
    21 }
    22 
    23 bool CCore::Initialize()
    24 {
    25     //do something
    26     return true;
    27 }
    28 
    29 void CCore::Uninitialize()
    30 {
    31     //do something
    32 }
    33 
    34 void CCore::SetRunState(bool bRunning)
    35 {
    36     m_bIsRuning = bRunning;
    37 }
    38 
    39 bool CCore::Breathe()
    40 {
    41     if (!m_bIsRuning)
    42         return false;
    43     static size_t c = 0;
    44     size_t now = time(NULL);
    45     if (now - c > 3)
    46     {
    47         c = now;
    48         if (!m_Script)
    49         {
    50             m_Script = new CLuaScript;
    51         }        
    52         if (m_Script)
    53         {
    54                 //游戏调用lua脚本
    55             m_Script->LoadScript("./../test.lua"); 
    56             //调用脚本函数,请参看下面第9点test.lua脚本
    57             m_Script->CallFunction("main", 1, "sdd", "luaer", c, c / 18);
    58         }
    59         else
    60         {
    61             std::cout << "new CLuaScript failed!" << std::endl;
    62             m_bIsRuning = false;
    63         }
    64     }
    65     return true;
    66 }

    8,最后是实现mian函数(也就是游戏的服务器)

     1 #include <iostream>
     2 #include "Core.h"
     3 using namespace std;
     4 
     5 int main(int argc, char* argv[])
     6 {
     7     if (!g_Core.Initialize())
     8     {
     9         g_Core.Uninitialize();
    10         return 0;
    11     }
    12     std::cout << "-----------------Start game!!!-----------------" << std::endl;
    13     while (1)
    14     {
    15         if (!g_Core.Breathe())
    16             break;
    17     }
    18     std::cout << "-----------------Game over!!!-----------------" << std::endl;
    19     g_Core.Uninitialize();
    20 
    21     system("PAUSE");
    22     return 1;
    23 }

    9,在工程目录下创建test.lua脚本给游戏调用

     1 function main(szName, num1, num2)
     2     print("main()", szName, num1, num2); --调用lua基础库函数
     3     local nRet = SayHello(szName, num1, num2); --调用游戏接口并返回结果
     4     print("nRet =", nRet);
     5     local nRand = math.random(100);
     6     print("nRand =", nRand)
     7     if nRand > 80 then
     8         StopGame(); --停止游戏
     9     end
    10     return 1;
    11 end

    运行结果:

     1 -----------------Start game!!!-----------------
     2 main()  luaer   1410876602      78382033
     3 Lua call c/c++:SayHello()
     4 Hello Everyone!
     5 My name is luaer
     6 nRet =  18
     7 nRand = 1
     8 main()  luaer   1410876606      78382033
     9 Lua call c/c++:SayHello()
    10 Hello Everyone!
    11 My name is luaer
    12 nRet =  18
    13 nRand = 57
    14 main()  luaer   1410876610      78382033
    15 Lua call c/c++:SayHello()
    16 Hello Everyone!
    17 My name is luaer
    18 nRet =  18
    19 nRand = 20
    20 main()  luaer   1410876614      78382034
    21 Lua call c/c++:SayHello()
    22 Hello Everyone!
    23 My name is luaer
    24 nRet =  18
    25 nRand = 81
    26 Lua call c/c++:StopGame()
    27 Game is over!
    28 -----------------Game over!!!-----------------
    29 Press any key to continue . . .

    Demo工程的完整版本可以通过github上获得。

  • 相关阅读:
    兼容ie8 rgba()用法
    WebUploader在display:none 无法运行
    text-overflow: ellipsis 在IE8中不能显示省略号的问题
    关于 href="javascript:;" 在IE8中的问题
    html中select的onchange打开方式
    angularJS 报错总结
    c:if的用法
    layui的编辑器 layedit的异步赋值问题
    Bootstrap- Modal对话框如何在关闭时触发事件
    Spring源码导入IDEA
  • 原文地址:https://www.cnblogs.com/borey/p/5622842.html
Copyright © 2011-2022 走看看