一,为什么要在游戏中应用脚本语言?
要解释这个问题首先咱们先来理解一下脚本语言的个性:
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