• 为什么要在游戏中使用脚本语言?

  要解释这个问题首先我们先来了解一下脚本语言的特性:

  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 <iostream>
#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 = ; 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')
{
std::cout << "Lua script file illegal!" << std::endl;
return false;
}
if (!m_LuaState)
return false; m_IsLoadScript = (luaL_dofile(m_LuaState, szFileName) == LUA_OK);
if (!m_IsLoadScript)
{
std::cout << "<LUA_LOAD_ERROR>"<< lua_tostring(m_LuaState, -) << std::endl;
lua_pop(m_LuaState, );
}
return m_IsLoadScript;
} bool CLuaScript::CallFunction(char* cFuncName, int nResults, char* cFormat, va_list vlist)
{
if (!m_LuaState || !m_IsLoadScript)
return false; double nNumber = ;
int nInteger = ;
char* cString = NULL;
void* pPoint = NULL;
int i = ;
int nArgnum = ;
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, ); if (nRetcode != )
{
std::cout << "<LUA_CALL_FUNC_ERROR>" << lua_tostring(m_LuaState, -) << std::endl;
lua_pop(m_LuaState, );
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 <direct.h>
#include <iostream>
#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) < )
return ;
const char* szName = lua_tostring(L, );
int nParam1 = lua_tonumber(L, );
int nParam2 = lua_tonumber(L, );
cout << "My name is " << szName << endl;
lua_pushnumber(L, nParam1 / nParam2);
return ;
} int LuaStopGame(lua_State* L)
{
cout << "Lua call c/c++:StopGame()" << endl;
cout << "Game is over!" << endl;
g_Core.SetRunState(false);
return ;
} //脚本接口
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" 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

Core.cpp

 #include "Core.h"
#include <time.h>
#include <iostream>
using namespace std; CCore g_Core; CCore::CCore()
{
m_Script = NULL;
m_bIsRuning = true;
} CCore::~CCore()
{
if (m_Script)
{
delete m_Script;
m_Script = NULL;
}
} bool CCore::Initialize()
{
//do something
return true;
} void CCore::Uninitialize()
{
//do something
} void CCore::SetRunState(bool bRunning)
{
m_bIsRuning = bRunning;
} bool CCore::Breathe()
{
if (!m_bIsRuning)
return false;
static size_t c = ;
size_t now = time(NULL);
if (now - c > )
{
c = now;
if (!m_Script)
{
m_Script = new CLuaScript;
}
if (m_Script)
{
//游戏调用lua脚本
m_Script->LoadScript("./../test.lua");
//调用脚本函数,请参看下面第9点test.lua脚本
m_Script->CallFunction("main", , "sdd", "luaer", c, c / );
}
else
{
std::cout << "new CLuaScript failed!" << std::endl;
m_bIsRuning = false;
}
}
return true;
}

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

 #include <iostream>
#include "Core.h"
using namespace std; int main(int argc, char* argv[])
{
if (!g_Core.Initialize())
{
g_Core.Uninitialize();
return ;
}
std::cout << "-----------------Start game!!!-----------------" << std::endl;
while ()
{
if (!g_Core.Breathe())
break;
}
std::cout << "-----------------Game over!!!-----------------" << std::endl;
g_Core.Uninitialize(); system("PAUSE");
return ;
}

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

 function main(szName, num1, num2)
print("main()", szName, num1, num2); --调用lua基础库函数
local nRet = SayHello(szName, num1, num2); --调用游戏接口并返回结果
print("nRet =", nRet);
local nRand = math.random();
print("nRand =", nRand)
if nRand > then
StopGame(); --停止游戏
end
return ;
end

运行结果:

 -----------------Start game!!!-----------------
main() luaer
Lua call c/c++:SayHello()
Hello Everyone!
My name is luaer
nRet =
nRand =
main() luaer
Lua call c/c++:SayHello()
Hello Everyone!
My name is luaer
nRet =
nRand =
main() luaer
Lua call c/c++:SayHello()
Hello Everyone!
My name is luaer
nRet =
nRand =
main() luaer
Lua call c/c++:SayHello()
Hello Everyone!
My name is luaer
nRet =
nRand =
Lua call c/c++:StopGame()
Game is over!
-----------------Game over!!!-----------------
Press any key to continue . . .

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

lua脚本在游戏中的应用的更多相关文章

  1. 【COCOS2DX-LUA 脚本开发之一】在Cocos2dX游戏中使用Lua脚本进行游戏开发(基础篇)并介绍脚本在游戏中详细用途!

    [COCOS2DX-LUA 脚本开发之一]在Cocos2dX游戏中使用Lua脚本进行游戏开发(基础篇)并介绍脚本在游戏中详细用途! 分类: [Cocos2dx Lua 脚本开发 ] 2012-04-1 ...

  2. lua学习:游戏中的Lua

    lua作为一种脚本语言,可以快速地开发游戏的原型.提高游戏的开发效率. 在游戏中,lua可以用来完成下面这些工作: ●编辑游戏的用户界面 ●定义.存储和管理基础游戏数据 ●管理实时游戏事件 ●创建和维 ...

  3. 在Unity3d中解析Lua脚本的方法

    由于近期项目中提出了热更新的需求,因此本周末在Lua的陪伴下度过.对Lua与Unity3d的搭配使用,仅仅达到了一个初窥门径的程度,记录一二于此.水平有限,欢迎批评指正. 网络上关于Lua脚本和Uni ...

  4. 在redis中使用lua脚本

    在实际工作过程中,可以使用lua脚本来解决一些需要保证原子性的问题,而且lua脚本可以缓存在redis服务器上,势必会增加性能. 不过lua也会有很多限制,在使用的时候要注意. 在Redis中执行Lu ...

  5. Redis学习笔记六:独立功能之 Lua 脚本

    Redis 2.6 开始支持 Lua 脚本,通过在服务器环境嵌入 Lua 环境,Redis 客户端中可以原子地执行多个 Redis 命令. 使用 eval 命令可以直接对输入的脚本求值: 127.0. ...

  6. Redis进阶实践之八Lua的Cjson在Linux下安装、使用和用C#调用Lua脚本

    一.引言         学习Redis也有一段时间了,感触还是颇多的,但是自己很清楚,路还很长,还要继续.上一篇文章简要的介绍了如何在Linux环境下安装Lua,并介绍了在Linux环境下如何编写L ...

  7. Redis进阶实践之十九 Redis如何使用lua脚本

    一.引言               redis学了一段时间了,基本的东西都没问题了.从今天开始讲写一些redis和lua脚本的相关的东西,lua这个脚本是一个好东西,可以运行在任何平台上,也可以嵌入 ...

  8. uLua学习之读取外部Lua脚本(四)

    前言 上节说到了Lua脚本与unity3d中C#脚本的数据交互,但是我感觉上节中的数理方式不太好,因为我们是把Lua脚本以字符串形式粘贴到C#脚本中的,如果读取配置数据都这样做的话,那就太可怕了.想想 ...

  9. 用C#调用Lua脚本

    用C#调用Lua脚本 一.引言 学习Redis也有一段时间了,感触还是颇多的,但是自己很清楚,路还很长,还要继续.上一篇文章简要的介绍了如何在Linux环境下安装Lua,并介绍了在Linux环境下如何 ...

随机推荐

  1. Boost::bind使用详解

    1.Boost::bind 在STL中,我们经常需要使用bind1st,bind2st函数绑定器和fun_ptr,mem_fun等函数适配器,这些函数绑定器和函数适配器使用起来比较麻烦,需要根据是全局 ...

  2. 简述Python入门小知识

    如今的Python开发工程师很受企业和朋友们的青睐,现在学习Python开发的小伙伴也很多,本篇文章就和大家探讨一下Python入门小知识都有哪些. 扣丁学堂简述Python入门小知识Python培训 ...

  3. 腾讯云的基本配置(centos 7.1)及mysql的使用

    因为想在微信上开发些东西,所以租用了一个月的腾讯云. 推荐选择的镜像是centos7.1.这个系统的选择和本地操作系统基本没有关系. 首先要登录到云主机中,用户名是root,密码是当初自己设置的那一个 ...

  4. 卓豪ManageEngine参加2018企业数字化转型与CIO职业发展高峰论坛

    卓豪ManageEngine参加2018企业数字化转型与CIO职业发展高峰论坛 2018年10月20日,78CIO APP在北京龙城温德姆酒店主办了主题为“新模式.新动能.新发展”的<2018企 ...

  5. 《Linux就该这么学》第三天课程

    秦时明月经典语录: 王道: 千里挥戈,万众俯首.四海江湖,百世王道.——项羽 今天主要介绍了常用系统工作的命令 如需进一步了解,请前往https://www.linuxcool.com(附带配音) r ...

  6. MFC源码解读(一)最原始一个MFC程序,手写不用向导

    从这一篇开始,详细记录一下MFC的源码解读 四个文件,分别为: stdafx.h,stdafx.cpp,hello.h,hello.cpp 代码如下: //stdafx.h #include < ...

  7. Python获取当前类的所有成员属性

    # -*- coding: utf-8 -*- class Market(object): def __init__(self): self.title = 'apple' self.count = ...

  8. Cura - CuraEngine - 架构分析

    参考: https://blog.csdn.net/justdoithai/article/details/52746094

  9. Do More With These Great Plugins for Windows Live Writer(old)

    This article is out of day,now we use open live wirter, but we don’t have so much works great plugin ...

  10. java web中的异常处理

    1.集中处理 参考:https://blog.csdn.net/weililansehudiefei/article/details/73691294