用Hge && Lua写游戏
<p> 作者:星海传说<br/> 以前一直用纯C++写程序,因为曾经坚信C++是最强大的语言,还因为致力于游戏开发,而在游戏世界中C\C++一直是老大。大三我和两个同伙做创新基金项目---“游戏AI”,还是用C++,图像是DX,但已明显感到不足:DX太散,需要重新包装;C++太硬,需要花大力气设计框架,灵活性也不够。。。<br/><br/> 初次接触Lua是在云风写的书《游戏之旅---我的编程感悟》里,当云风说到梦幻西游大部分代码是用lua写的时感到很不可思议,看了下lua语法反而觉得不如C++漂亮。后来想通了,脚本有着C++无可比拟的灵活优势,脚本即可当代码也可当数据文件,以往用C++忌讳的硬编码在脚本里反而不是什么问题。除了lua,还有python,perl,ruby等可选择,不过既然云风大侠强烈推荐那我就相信他的判断力。事实上,Lua可算是执行最快的脚本语言之一,据说魔兽世界都用的它。然而Lua的语法,特别是它和C++的接口很让我不爽,还要“弹栈压栈”类似汇编,对于我这种懒人来说无疑是天大的问题。还好找到了luabind,通过它可以很方便得和C++联系起来,经过几番试验终于决定用它了。<br/><br/> 游戏图像方面以前都靠同伙用DX做,但后来发现还得靠自己,DX太底层要自己写很多东西,我需要的是一款方便好用的2D游戏图像引擎。半年前就接触hge了,不过当时没在意,后来又看了下SDL,这个很好用但我缺发现载不进jpg图,所以又回到了hge的怀抱。明确了吧,我的第一个真正意义上的游戏作品兼毕业设计,将采用hge+lua+luabind的方式开发。<br/><br/> 突然发现不如写个“连载”,以往都是看高手们的,现在自己居然也可以写点了,呵呵。先发个今天做好的demo图,教程慢慢写。。。 <br/><br/><img id="UserImg" alt="1.jpgwidth: 803 px
size: -1 bytes
double click to view all" src="http://www.ogdev.net/bbs/ShowFile.asp?ID=54498&EXT=JPG" width="600" border="0" name="UserImg" loaded="loaded" style="ZOOM: 120%;"/><br/>100个人 <br/></p><p> 开始吧,首先从网上下载Lua(我是5.1.1),Luabind(我是0.7),Hge(我是1.6)和Boost库。由于我用的是VC8,但原来的库是VC6或7编译的,所以需要将这些库的源代码重新编译,得到lib和dll文件。然后按着教程写些代码,链上库,保证能够顺利执行。这里注意几点:<br/> 1.luabind似乎应该分别用debug和release模式编译,我得到的是luabindd.lib和luabindr.lib,使用时若是debug模式就链luabindd.lib,release就luabindr.lib<br/> 2.VC8取消了单线程模式和以往会不兼容,所以你的工程及依赖的库应该保证编译链接的一致性,就是用同一个编译链接选项。<br/> 3.Lua5.1和之前版本有很多不同,具体自己去网上搜。<br/> 4.也许还会遇到其他问题,我当时就差点放弃,坚持下来,多试试,遇到不懂的先google再问人。<br/> <br/> 确认这3个库可以正常工作后就可以开始写游戏了,你还需要做的是找一些参考资料(lua,luabind,hge的官方手册及其他文档)和加入几个相关的技术群,这里推荐"中国HGE"(QQ:14159676)。<br/> 建一个Win32工程,把该载的头文件载进去。<br/>// Windows 头文件:<br/>#include <windows.h><br/><br/>// C 运行时头文件<br/>#include <stdlib.h><br/>#include <malloc.h><br/>#include <memory.h><br/>#include <tchar.h><br/><br/>//hge头文件<br/>#include <hge.h><br/>#include <hgecolor.h><br/>#include <hgesprite.h><br/>#include <hgedistort.h><br/>#include <hgefont.h><br/><br/>//stl头文件<br/> <br/>//lua头文件<br/>extern "C"<br/>{<br/> #include "lua.h"<br/> #include "lualib.h"<br/> #include "lauxlib.h"<br/>}<br/><br/>//luabind头文件<br/>#include <luabind/luabind.hpp><br/>#include <luabind/object.hpp><br/>#include <luabind/class.hpp><br/> <br/><br/> 由于我的方案是用luabind将hge类及相关函数映射到lua中,所以你需要按照luabind的方法进行包装,要注意的是由于hge类是个虚基类,所以你还得另外写个类对其进行包装。映射函数时注意参数或返回值为指针的情况,还有不定参数,都是不行的。<br/><br/> Bind.h<br/><br/>namespace tg<br/>{<br/><br/>namespace Bind<br/>{<br/> //绑定hge<br/> void Bind_HgeSys(lua_State* L); <br/> //绑定hgeFont<br/> void Bind_HgeFont(lua_State* L);<br/> //绑定hgeSprite<br/> void Bind_HgeSprite(lua_State* L);<br/> }<br/><br/>}<br/> <br/><br/>Bind.cpp<br/><br/>//绑定hge<br/>void Bind::Bind_HgeSys(lua_State* L)<br/>{<br/> module(L)<br/> [ <br/> class_<HgeSys>("HgeSys") <br/> .def(constructor<>()) <br/> .scope<br/> [ <br/> def("System_Start",&HgeSys::System_Start), <br/><br/> def("System_SetStateBool", &HgeSys::System_SetStateBool),<br/> def("System_SetStateInt", &HgeSys::System_SetStateInt),<br/> def("System_SetStateString", &HgeSys::System_SetStateString), <br/><br/> //def("Resource_Load",&HgeSys::Resource_Load), //这两个有问题<br/> //def("Resource_Free",&HgeSys::Resource_Free), <br/> def("Resource_AttachPack",&HgeSys::Resource_AttachPack), <br/><br/> ......<br/><br/> ]<br/> ];<br/>}<br/><br/>//绑定hgeFont<br/>void Bind::Bind_HgeFont(lua_State* L)<br/>{<br/> module(L)<br/> [<br/> class_<hgeFont>("HgeFont")<br/> .def(constructor<const char*>())<br/> .def(constructor<const hgeFont&>())<br/> .def("Render",&hgeFont::Render)<br/> ...... <br/> ];<br/>}<br/><br/>//绑定hgeSprite<br/>void Bind::Bind_HgeSprite(lua_State* L)<br/>{<br/> module(L)<br/> [<br/> class_<hgeSprite>("HgeSprite")<br/> .def(constructor<HTEXTURE,float, float, float, float>())<br/> .def(constructor<const hgeSprite&>())<br/> .def("Render",&hgeSprite::Render)<br/> ...... <br/> ];<br/>}<br/> <br/><br/>注意,这里我绑定的是HgeSys而非Hge类,因为Hge是个虚基类,不能直接用luabind,所以在其上包装了一层。<br/><br/>HgeSys.h<br/><br/>namespace tg<br/>{<br/><br/>class HgeSys<br/>{<br/>public:<br/> HgeSys();<br/> ~HgeSys();<br/><br/> static void System_Start(); //启动hge循环 <br/><br/> //设置hge状态<br/> static void System_SetStateBool(hgeBoolState state, bool value);<br/> static void System_SetStateInt(hgeIntState state, int value);<br/> static void System_SetStateString(hgeStringState state, const char* value); <br/><br/> //其他函数<br/><br/> //HGE interface<br/> static HGE* hge; <br/><br/>};<br/><br/>}<br/> <br/><br/>还得建一个脚本引擎类来负责lua脚本的打开,初始化,执行等。<br/><br/>//ScriptEngine.h<br/><br/>namespace tg<br/>{<br/><br/>class ScriptEngine<br/>{<br/>public:<br/> ScriptEngine();<br/> ~ScriptEngine();<br/><br/> void Init(); //初始化<br/> void Release(); //结束<br/> bool Render(); //图像绘制<br/> bool Update(); //消息处理和逻辑更新<br/><br/>private:<br/> lua_State* L;<br/>};<br/><br/>}<br/><br/>//---------------ScriptEngine.cpp里---------------------<br/><br/>//构造函数<br/>ScriptEngine::ScriptEngine()<br/>{<br/> L = luaL_newstate();<br/> lua_cpcall(L, luaopen_base, 0);<br/> lua_cpcall(L, luaopen_io, 0);<br/> lua_cpcall(L, luaopen_string, 0);<br/> lua_cpcall(L, luaopen_table, 0);<br/> lua_cpcall(L, luaopen_math, 0);<br/> lua_cpcall(L, luaopen_debug, 0); <br/> lua_cpcall(L, luaopen_os, 0);<br/><br/> open(L);<br/> //邦定C++到Lua<br/> Bind::Bind_HgeSys(L);<br/> Bind::Bind_HgeFont(L); <br/> Bind::Bind_HgeSprite(L);<br/> Bind::Bind_DebugConsole(L);<br/><br/> int s = luaL_loadfile(L, "Script//GameInit.lua");<br/> if ( s==0 )<br/> { <br/> s = lua_pcall(L, 0, LUA_MULTRET, 0); //启动lua初始文件<br/> } <br/>}<br/><br/>//析构函数<br/>ScriptEngine::~ScriptEngine()<br/>{<br/> lua_close(L);<br/>}<br/>//初始化<br/>void ScriptEngine::Init()<br/>{ <br/> luabind::call_function<void>(L,"EngineInit"); //脚本引擎初始化<br/>}<br/><br/>//结束<br/>void ScriptEngine::Release()<br/>{<br/> luabind::call_function<void>(L,"EngineRelease"); //脚本引擎结束 <br/>}<br/><br/>//图像绘制<br/>bool ScriptEngine::Render()<br/>{<br/> return luabind::call_function<bool>(L,"EngineRender");<br/>}<br/><br/>//消息处理和逻辑更新<br/>bool ScriptEngine::Update()<br/>{<br/> return luabind::call_function<bool>(L,"EngineUpdate");<br/>}<br/> <br/><br/></p>
[此贴子已经被作者于2007-1-27 15:19:24编辑过]
C++部分还剩下的就是main函数了,这里建立了HgeSys,ScriptEngine的对象,绑定RenderFunc和FrameFunc函数到Hge,然后启动Hge,执行相关函数。。<br/>#include "stdafx.h"<br/>#include "HgeSys.h"<br/>#include "ScriptEngine.h"<br/>#include "DebugConsole.h"<br/>using namespace tg;<br/><br/>DebugConsole debugConsole; //这个是开console窗口调试用的<br/>tg::HgeSys hgeSys; //封装Hge接口的类<br/>tg::ScriptEngine scriptEngine; //脚本引擎<br/><br/><br/>/////////////////////////<br/>bool FrameFunc()<br/>{ <br/> return scriptEngine.Update(); <br/>}<br/><br/>bool RenderFunc()<br/>{<br/> // Render scene <br/> HgeSys::hge->Gfx_BeginScene(); <br/> <br/> scriptEngine.Render(); <br/><br/> HgeSys::hge->Gfx_EndScene();<br/> return false;<br/>}<br/><br/><br/>//Main<br/>int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)<br/>{ <br/> HgeSys::hge->System_SetState(HGE_FRAMEFUNC, FrameFunc);<br/> HgeSys::hge->System_SetState(HGE_RENDERFUNC, RenderFunc); <br/><br/> if(HgeSys::hge->System_Initiate())<br/> {<br/> scriptEngine.Init(); //脚本引擎初始化 <br/> HgeSys::hge->System_Start(); //hge执行,进入游戏引擎循环<br/> scriptEngine.Release(); //脚本引擎结束 <br/> } <br/> <br/> return 0;<br/>}<br/> <br/><br/>最后说下Lua部分,我的是GameInit.lua进行初始化工作,GameEngine.lua是游戏6引擎部分,也有Init,Render,Update,Release等方法。<br/> ------------GameInit.lua---------------------<br/><br/>---------------------初始化hge状态---------------------------------<br/>HgeSys.System_SetStateString(16, "GameEngine.log") --HGE_LOGFILE<br/>HgeSys.System_SetStateString(7, "GameEngine") --HGE_TITLE<br/>HgeSys.System_SetStateBool(18, false) --HGE_USESOUND<br/>HgeSys.System_SetStateBool(11, true) --HGE_WINDOWED<br/>HgeSys.System_SetStateBool(25, false) --HGE_HIDEMOUSE<br/>HgeSys.System_SetStateInt(8, 800) --HGE_SCREENWIDTH<br/>HgeSys.System_SetStateInt(9, 600) --HGE_SCREENHEIGHT<br/>HgeSys.System_SetStateInt(10, 32) --HGE_SCREENBPP<br/><br/><br/>---------------------游戏引擎-------------------------------------<br/>dofile("Script//GameEngine.lua")<br/><br/>gameEngine = GameEngine() --全局游戏引擎对象<br/><br/><br/>---------------------Globa function--------------------------------游戏引擎初始化,由C++调用<br/>function EngineInit()<br/> gameEngine:Init() <br/>end<br/><br/>--绘制图像<br/>function EngineRender()<br/> return gameEngine:Render()<br/>end<br/><br/>--消息处理和逻辑更新<br/>function EngineUpdate()<br/> return gameEngine:Update()<br/>end<br/><br/>--资源释放<br/>function EngineRelease()<br/> gameEngine:Release()<br/>end<br/> <br/>----------GameEngine.lua游戏引擎,由Hge调用-------------------<br/><br/><br/>class 'GameEngine' --这种语法是需要luabind才能写的!<br/><br/>function GameEngine:__init() <br/>end<br/><br/>function GameEngine:Init() --初始化 <br/>end<br/><br/>function GameEngine:Render() --图像绘制 <br/> return false <br/>end<br/><br/>function GameEngine:Update() --消息处理 & 逻辑更新 <br/> return false <br/>end<br/><br/>function GameEngine:Release() --资源释放 <br/>end<br/>
页:
[1]