人气 215

[游戏程序] 用Hge && Lua写游戏 [复制链接]

九艺网 2017-3-10 17:01:17

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?注册

x
作者:星海传说
     以前一直用纯C++写程序,因为曾经坚信C++是最强大的语言,还因为致力于游戏开发,而在游戏世界中C\C++一直是老大。大三我和两个同伙做创新基金项目---“游戏AI”,还是用C++,图像是DX,但已明显感到不足:DX太散,需要重新包装;C++太硬,需要花大力气设计框架,灵活性也不够。。。

     初次接触Lua是在云风写的书《游戏之旅---我的编程感悟》里,当云风说到梦幻西游大部分代码是用lua写的时感到很不可思议,看了下lua语法反而觉得不如C++漂亮。后来想通了,脚本有着C++无可比拟的灵活优势,脚本即可当代码也可当数据文件,以往用C++忌讳的硬编码在脚本里反而不是什么问题。除了lua,还有python,perl,ruby等可选择,不过既然云风大侠强烈推荐那我就相信他的判断力。事实上,Lua可算是执行最快的脚本语言之一,据说魔兽世界都用的它。然而Lua的语法,特别是它和C++的接口很让我不爽,还要“弹栈压栈”类似汇编,对于我这种懒人来说无疑是天大的问题。还好找到了luabind,通过它可以很方便得和C++联系起来,经过几番试验终于决定用它了。

     游戏图像方面以前都靠同伙用DX做,但后来发现还得靠自己,DX太底层要自己写很多东西,我需要的是一款方便好用的2D游戏图像引擎。半年前就接触hge了,不过当时没在意,后来又看了下SDL,这个很好用但我缺发现载不进jpg图,所以又回到了hge的怀抱。明确了吧,我的第一个真正意义上的游戏作品兼毕业设计,将采用hge+lua+luabind的方式开发。

     突然发现不如写个“连载”,以往都是看高手们的,现在自己居然也可以写点了,呵呵。先发个今天做好的demo图,教程慢慢写。。。


                               
登录/注册后可看大图

100个人

   开始吧,首先从网上下载Lua(我是5.1.1),Luabind(我是0.7),Hge(我是1.6)和Boost库。由于我用的是VC8,但原来的库是VC6或7编译的,所以需要将这些库的源代码重新编译,得到lib和dll文件。然后按着教程写些代码,链上库,保证能够顺利执行。这里注意几点:
     1.luabind似乎应该分别用debug和release模式编译,我得到的是luabindd.lib和luabindr.lib,使用时若是debug模式就链luabindd.lib,release就luabindr.lib
     2.VC8取消了单线程模式和以往会不兼容,所以你的工程及依赖的库应该保证编译链接的一致性,就是用同一个编译链接选项。
     3.Lua5.1和之前版本有很多不同,具体自己去网上搜。
     4.也许还会遇到其他问题,我当时就差点放弃,坚持下来,多试试,遇到不懂的先google再问人。

     确认这3个库可以正常工作后就可以开始写游戏了,你还需要做的是找一些参考资料(lua,luabind,hge的官方手册及其他文档)和加入几个相关的技术群,这里推荐"中国HGE"(QQ:14159676)。
     建一个Win32工程,把该载的头文件载进去。
// Windows 头文件:
#include

// C 运行时头文件
#include
#include
#include
#include

//hge头文件
#include
#include
#include
#include
#include

//stl头文件

//lua头文件
extern "C"
{
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}

//luabind头文件
#include
#include
#include


    由于我的方案是用luabind将hge类及相关函数映射到lua中,所以你需要按照luabind的方法进行包装,要注意的是由于hge类是个虚基类,所以你还得另外写个类对其进行包装。映射函数时注意参数或返回值为指针的情况,还有不定参数,都是不行的。

   Bind.h

namespace tg
{

namespace Bind
{
//绑定hge
void Bind_HgeSys(lua_State* L);  
//绑定hgeFont
void Bind_HgeFont(lua_State* L);
//绑定hgeSprite
void Bind_HgeSprite(lua_State* L);
}

}


Bind.cpp

//绑定hge
void Bind::Bind_HgeSys(lua_State* L)
{
module(L)
[  
class_("HgeSys")
  .def(constructor())   
  .scope
  [   
   def("System_Start",&HgeSys::System_Start),      

   def("System_SetStateBool", &HgeSys::System_SetStateBool),
   def("System_SetStateInt", &HgeSys::System_SetStateInt),
   def("System_SetStateString", &HgeSys::System_SetStateString),   

   //def("Resource_Load",&HgeSys::Resource_Load), //这两个有问题
   //def("Resource_Free",&HgeSys::Resource_Free),     
   def("Resource_AttachPack",&HgeSys::Resource_AttachPack),   

   ......

  ]
];
}

//绑定hgeFont
void Bind::Bind_HgeFont(lua_State* L)
{
module(L)
    [
class_("HgeFont")
   .def(constructor())
   .def(constructor())
   .def("Render",&hgeFont::Render)
   ......  
];
}

//绑定hgeSprite
void Bind::Bind_HgeSprite(lua_State* L)
{
module(L)
    [
class_("HgeSprite")
   .def(constructor())
   .def(constructor())
   .def("Render",&hgeSprite::Render)
   ......   
];
}


注意,这里我绑定的是HgeSys而非Hge类,因为Hge是个虚基类,不能直接用luabind,所以在其上包装了一层。

HgeSys.h

namespace tg
{

class HgeSys
{
public:
HgeSys();
~HgeSys();

static void System_Start(); //启动hge循环

//设置hge状态
static void System_SetStateBool(hgeBoolState state, bool value);
static void System_SetStateInt(hgeIntState state, int value);
static void System_SetStateString(hgeStringState state, const char* value);

  //其他函数

  //HGE interface
static HGE* hge;  

};

}


还得建一个脚本引擎类来负责lua脚本的打开,初始化,执行等。

//ScriptEngine.h

namespace tg
{

class ScriptEngine
{
public:
ScriptEngine();
~ScriptEngine();

void Init();    //初始化
void Release(); //结束
bool Render();  //图像绘制
bool Update();  //消息处理和逻辑更新

private:
lua_State* L;
};

}

//---------------ScriptEngine.cpp里---------------------

//构造函数
ScriptEngine::ScriptEngine()
{
L = luaL_newstate();
lua_cpcall(L, luaopen_base, 0);
lua_cpcall(L, luaopen_io, 0);
lua_cpcall(L, luaopen_string, 0);
lua_cpcall(L, luaopen_table, 0);
lua_cpcall(L, luaopen_math, 0);
lua_cpcall(L, luaopen_debug, 0);
lua_cpcall(L, luaopen_os, 0);

open(L);
//邦定C++到Lua
Bind::Bind_HgeSys(L);
Bind::Bind_HgeFont(L);
Bind::Bind_HgeSprite(L);
Bind::Bind_DebugConsole(L);

int s = luaL_loadfile(L, "Script//GameInit.lua");
if ( s==0 )
{  
  s = lua_pcall(L, 0, LUA_MULTRET, 0); //启动lua初始文件
    }
}

//析构函数
ScriptEngine::~ScriptEngine()
{
lua_close(L);
}
//初始化
void ScriptEngine::Init()
{
luabind::call_function(L,"EngineInit"); //脚本引擎初始化
}

//结束
void ScriptEngine::Release()
{
luabind::call_function(L,"EngineRelease"); //脚本引擎结束
}

//图像绘制
bool ScriptEngine::Render()
{
return luabind::call_function(L,"EngineRender");
}

//消息处理和逻辑更新
bool ScriptEngine::Update()
{
return luabind::call_function(L,"EngineUpdate");
}



[此贴子已经被作者于2007-1-27 15:19:24编辑过]

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

QQ|手机版|小黑屋|九艺游戏动画论坛 ( 津ICP备2022000452号-1 )

GMT+8, 2024-3-29 01:04 , Processed in 0.125327 second(s), 23 queries .

Powered by Discuz! X3.4  © 2001-2017 Discuz Team.