popo 发表于 2007-1-27 15:17:00

用Hge && Lua写游戏

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

popo 发表于 2007-1-27 15:17:00

C++部分还剩下的就是main函数了,这里建立了HgeSys,ScriptEngine的对象,绑定RenderFunc和FrameFunc函数到Hge,然后启动Hge,执行相关函数。。<br/>#include&nbsp;"stdafx.h"<br/>#include&nbsp;"HgeSys.h"<br/>#include&nbsp;"ScriptEngine.h"<br/>#include&nbsp;&nbsp;"DebugConsole.h"<br/>using&nbsp;namespace&nbsp;tg;<br/><br/>DebugConsole&nbsp;debugConsole;&nbsp;&nbsp;&nbsp;//这个是开console窗口调试用的<br/>tg::HgeSys&nbsp;hgeSys;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//封装Hge接口的类<br/>tg::ScriptEngine&nbsp;scriptEngine;&nbsp;&nbsp;//脚本引擎<br/><br/><br/>/////////////////////////<br/>bool&nbsp;FrameFunc()<br/>{&nbsp;<br/>&nbsp;return&nbsp;scriptEngine.Update();&nbsp;<br/>}<br/><br/>bool&nbsp;RenderFunc()<br/>{<br/>&nbsp;//&nbsp;Render&nbsp;scene&nbsp;<br/>&nbsp;HgeSys::hge-&gt;Gfx_BeginScene();&nbsp;&nbsp;<br/>&nbsp;&nbsp;<br/>&nbsp;scriptEngine.Render();&nbsp;<br/><br/>&nbsp;HgeSys::hge-&gt;Gfx_EndScene();<br/>&nbsp;return&nbsp;false;<br/>}<br/><br/><br/>//Main<br/>int&nbsp;WINAPI&nbsp;WinMain(HINSTANCE,&nbsp;HINSTANCE,&nbsp;LPSTR,&nbsp;int)<br/>{&nbsp;<br/>&nbsp;HgeSys::hge-&gt;System_SetState(HGE_FRAMEFUNC,&nbsp;FrameFunc);<br/>&nbsp;HgeSys::hge-&gt;System_SetState(HGE_RENDERFUNC,&nbsp;RenderFunc);&nbsp;<br/><br/>&nbsp;if(HgeSys::hge-&gt;System_Initiate())<br/>&nbsp;{<br/>&nbsp;&nbsp;scriptEngine.Init();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//脚本引擎初始化&nbsp;&nbsp;&nbsp;&nbsp;<br/>&nbsp;&nbsp;HgeSys::hge-&gt;System_Start();&nbsp;//hge执行,进入游戏引擎循环<br/>&nbsp;&nbsp;scriptEngine.Release();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//脚本引擎结束&nbsp;<br/>&nbsp;}&nbsp;<br/>&nbsp;<br/>&nbsp;return&nbsp;0;<br/>}<br/>&nbsp;<br/><br/>最后说下Lua部分,我的是GameInit.lua进行初始化工作,GameEngine.lua是游戏6引擎部分,也有Init,Render,Update,Release等方法。<br/>

popo 发表于 2007-1-27 15:18:00

------------GameInit.lua---------------------<br/><br/>---------------------初始化hge状态---------------------------------<br/>HgeSys.System_SetStateString(16,&nbsp;"GameEngine.log")&nbsp;&nbsp;--HGE_LOGFILE<br/>HgeSys.System_SetStateString(7,&nbsp;"GameEngine")&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;--HGE_TITLE<br/>HgeSys.System_SetStateBool(18,&nbsp;false)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;--HGE_USESOUND<br/>HgeSys.System_SetStateBool(11,&nbsp;true)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;--HGE_WINDOWED<br/>HgeSys.System_SetStateBool(25,&nbsp;false)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;--HGE_HIDEMOUSE<br/>HgeSys.System_SetStateInt(8,&nbsp;800)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;--HGE_SCREENWIDTH<br/>HgeSys.System_SetStateInt(9,&nbsp;600)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;--HGE_SCREENHEIGHT<br/>HgeSys.System_SetStateInt(10,&nbsp;32)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;--HGE_SCREENBPP<br/><br/><br/>---------------------游戏引擎-------------------------------------<br/>dofile("Script//GameEngine.lua")<br/><br/>gameEngine&nbsp;=&nbsp;GameEngine()&nbsp;&nbsp;--全局游戏引擎对象<br/><br/><br/>---------------------Globa&nbsp;function--------------------------------游戏引擎初始化,由C++调用<br/>function&nbsp;EngineInit()<br/>&nbsp;&nbsp;&nbsp;&nbsp;gameEngine:Init()&nbsp;&nbsp;&nbsp;<br/>end<br/><br/>--绘制图像<br/>function&nbsp;EngineRender()<br/>&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;gameEngine:Render()<br/>end<br/><br/>--消息处理和逻辑更新<br/>function&nbsp;EngineUpdate()<br/>&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;gameEngine:Update()<br/>end<br/><br/>--资源释放<br/>function&nbsp;EngineRelease()<br/>&nbsp;&nbsp;&nbsp;&nbsp;gameEngine:Release()<br/>end<br/>&nbsp;<br/>----------GameEngine.lua游戏引擎,由Hge调用-------------------<br/><br/><br/>class&nbsp;'GameEngine'&nbsp;&nbsp;&nbsp;--这种语法是需要luabind才能写的!<br/><br/>function&nbsp;GameEngine:__init()&nbsp;&nbsp;&nbsp;<br/>end<br/><br/>function&nbsp;GameEngine:Init()&nbsp;--初始化&nbsp;&nbsp;&nbsp;<br/>end<br/><br/>function&nbsp;GameEngine:Render()&nbsp;--图像绘制&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;false&nbsp;&nbsp;&nbsp;&nbsp;<br/>end<br/><br/>function&nbsp;GameEngine:Update()&nbsp;&nbsp;--消息处理&nbsp;&amp;&nbsp;逻辑更新&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;false&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br/>end<br/><br/>function&nbsp;GameEngine:Release()&nbsp;--资源释放&nbsp;<br/>end<br/>
页: [1]
查看完整版本: 用Hge && Lua写游戏