无意中发现了HGE中文社区,听朋友介绍,认识了HGE,然后开始对它进行研究,并使用HGE开始制作游戏。
因为我所得的资料基本上都是来源于各位高手的无私翻译,所以,我打算也做一些贡献出来,在这里写一篇HGE的基础教程,供刚接触HGE的朋友研究学习。
教程中可能会出现一些错误,请大家及时指正。由于我也是初学者,包括C++,也只是一个初学者,所以写出的教程可能质量并不高,也请大家谅解。
另外,学习此教程需要C++的基本知识,不需要非常高深,只需要了解函数调用、结构体、枚举、常量、变量、类的基本知识、函数指针等基本知识即可。
关于转载:
本教程可以随处转载,我的名字就不用了,不过请著名来源于HGEChina中文论坛:http://www.hgechina.com/,我们将对此表示感谢。
我使用的编译器:
我使用的编译器是Microsoft的Visual C++ 2005,但是Visual C++ 6.0或者Visual C++ 2003等VisualStudio的C++编译器都是可以使用HGE的,另外,BorlandC++也是可以使用HGE的,本教程将使用Visual Studio 2005为大家做讲解,如果有一些编译器问题上的出入,请大家搜索或者提问解决。
HGE基础教程第一章:初识HGE
C++有一个理念,我记得是在我看C++ Primer学习时看到的,那就是一次代码编写,处处使用,所以,就出现了诸如DLL,LIB等便于大家使用的代码库。其思想基本就是把写好的代码打包,然后只要在工程中链接lib或dll,就可以使用dll或者lib中写好的代码,它们的出现,为资源共享创造了空前的便利。那么,HGE也是贯彻这个思想的一个库,它把DirectX进行封装,方便大家使用,由于直接使用DirectX需要直接接触硬件上的东西,所以不利于入门,HGE的出现,让高效图形编程成为了简单的东西。
关于免费:
HGE是一个完全免费的,并且开源的引擎,所以我们可以随便使用在自己的商业或非商业项目,在此,我们也向HGE的编写者致敬。
激动人心的时刻:第一个HGE程序。
创建工程:
我们在Visual C++中新建一个WIN32工程,选择Win32控制台程序/Win32 console,为你的项目起一个名字。选择一个目录保存你的项目,点击确定-下一步。
选择Windows应用程序,并选择“空项目”/“empty Project”。点击确定,工程创建完毕,项目文件和代码就保存在刚才你选择的目录里。
工程的设置:
创建好工程后,我们需要进行一些设置,在左边的解决方案管理器中,看到你的项目名称,点右键,选择【属性R】
打开属性窗口后,点击C/C++,将右边的附加包含目录设置到你存放HGE引擎头文件的目录下,一般情况下,下载了hge引擎解压后,在hge目录下的include目录下。
设置完成后,再双击左边的链接器,打开子选项后,点【常规】,右边的附加库目录,选到hge目录下的lib/vc/目录
再点击左边的【输入】,右边附加依赖项:hge.lib、hgehelp.lib
如此一来,工程就设置好了。
好了,我们首先创建一个任意名字的.cpp文件。敲入以下代码:
另:解释,我就不写了,程序很简短,注释也很清楚。大家编译即可创建出第一个HGE程序了。怎么样,很简单吧!
代码: 写道: |
#include "hge.h"//包含hge头文件 HGE *hge=0;//创建一个指向hge类的指针。 bool RenderFunc()//绘制函数,程序开始后HGE将不停调用它 { return false;//程序正常时总是返回false,返回true将从System_Start往下执行 } bool FrameFunc()//逻辑函数,程序开始后HGE将不停调用它,一些逻辑判断或者处理可以写在这里。 { return false;//总是返回false } int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)//WinMain函数,程序的入口。 { hge=hgeCreate(HGE_VERSION);//使用hgeCreate函数创建HGE接口,参数必须传递正确的HGE_VERSION,它是在hge.h中定义的 hge->System_SetState(HGE_SCREENWIDTH, 800);//将屏幕宽度设置为800 hge->System_SetState(HGE_SCREENHEIGHT,600);//将屏幕高度设置为600 hge->System_SetState(HGE_FRAMEFUNC, FrameFunc);//设置逻辑函数为FrameFunc函数 hge->System_SetState(HGE_RENDERFUNC,RenderFunc);//设置绘制函数为RenderFunc函数 hge->System_SetState(HGE_TITLE, "我的第一个HGE程序");//设置窗口标题为“我的第一个HGE程序” hge->System_SetState(HGE_WINDOWED,true);//设置使用窗口模式 hge->System_SetState(HGE_USESOUND,false);//设置不使用声音(第一个程序我们先不讲解声音和图像的知识) if(hge->System_Initiate())//用hge类的System_Initiate()方法,检测初始化是否有错误出现。 { hge->System_Start();//如果没有问题,则使用System_Start方法,开始程序。 } hge->System_ShutDown();//程序停止 hge->Release();//释放HGE所占用的内存。 } |
以上代码应该比较简单易懂,那么,我说一点小东西,是大家需要留意一下的。
一:请注意HGE HeadFile和dll的版本匹配,如果两个东西的版本不匹配的话,程序是会出错的,举个例子,比如你用了hge 1.7的头文件,而使用hge 1.8的dll,那么就会报错。
二:如果你发现了程序开始会有hge的LOGO,那么不用担心,它并不是需要付费才可以解除的,我们只需要加入这一句:h->System_SetState(HGE_SHOWSPLASH,false);即可解除掉程序开头HGE的LOGO。
三:关于FrameFunc和RenderFunc的返回值,RenderFunc需要一直返回false,这貌似是HGE的一个规则,必须这么写,但是FrameFunc就不一样了,如果返回了true,程序就会从hge->System_Start();函数下面继续运行,运行到了 shutdown,程序就结束了。所以,有时候返回true是结束程序的好方法,而不是随地乱扔System_ShutDown和 System_Release函数。
HGE基础教程第二章:可以看到的东西--图像显示
图像显示,是所有程序,包括Windows操作系统在内必不可少的部分,代码编写者(程序员)将美工绘制好的图像显示到程序中,让使用者更加直观的看到程序的意图。废话就不多说了,这里我们来讲一下在HGE中,怎么显示图像,我相信跟我一样,大多数朋友在刚刚接触一个图像引擎的时候最关心的就是这个部分。OK,我们看下去。
HTEXTURE:
这是HGE中定义的一个数据类型,用来保存我们加载的图像,Texture的意思是“纹理”,说白了就是图片,当然,当你的程序越来越复杂的时候,你会很乐意接受这种很规范的命名。我们现在只需要知道,这是一个数据类型,至于怎么把图像加载、释放、显示,我们下面一一道来
屏幕上的精灵--hgeSprite类:
精灵,看起来很有意思的名字,但是很简单,它就是呈现图像的一个工具,每一个精灵都有一些属性,包括它的图像,关于这个,可以在置顶贴中找到hgeSprite类的全面资料。并且附加了代码。
灵魂部分:代码
说了那么多,不如一段代码来的实在,同样,我将保留以上简洁明了的代码风格,让大家很方便的读懂它,并且会有详尽的注释:
另外,请用具体的参数替代代码中红字部分
代码: 写道: |
#include "hge.h" #include "hgeSprite.h" HGE *hge=0;//创建HGE指针 hgeSprite *spr;//创建精灵类指针 HTEXTURE tex;//定义一个texture(纹理)对象 bool RenderFunc()//绘制函数,程序开始后HGE将不停调用它 { hge->Gfx_BeginScene();//开始渲染 hge->Gfx_Clear(0xFF000000);//以某颜色清屏,OxFF000000为透明度为0的黑色 spr->Render(显示位置X,显示位置Y);//在指定位置显示精灵 hge->Gfx_EndScene();//结束渲染 return false;//总是返回false } bool FrameFunc()//逻辑函数,程序开始后HGE将不停调用它,一些逻辑判断或者处理可以写在这里。 { return false;//程序正常时总是返回false,返回true将从System_Start往下执行 } int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)//WinMain函数,程序的入口。 { hge=hgeCreate(HGE_VERSION);//使用hgeCreate函数创建HGE接口,参数必须传递正确的HGE_VERSION,它是在hge.h中定义的 hge->System_SetState(HGE_SCREENWIDTH, 800);//将屏幕宽度设置为800 hge->System_SetState(HGE_SCREENHEIGHT,600);//将屏幕高度设置为600 hge->System_SetState(HGE_FRAMEFUNC, FrameFunc);//设置逻辑函数为FrameFunc函数 hge->System_SetState(HGE_RENDERFUNC,RenderFunc);//设置绘制函数为RenderFunc函数 hge->System_SetState(HGE_TITLE, "显示图像");//设置窗口标题为“显示图像” hge->System_SetState(HGE_WINDOWED,true);//设置使用窗口模式 hge->System_SetState(HGE_USESOUND,false);//设置不使用声音(第二个程序我们先不讲解声音的知识) if(hge->System_Initiate())//用hge类的System_Initiate()方法,检测初始化是否有错误出现。 { tex=hge->Texture_Load("图片路径和后缀,这里是相对目录,vc++2005是debug目录");//根据路径载入图片 if(tex)//检测是否图片成功载入 spr=new hgeSprite(tex,图片的显示起始位置X,起始位置Y,图片宽,图片高);//初始化精灵spr,并且指定tex为它的纹理 hge->System_Start();//如果没有问题,则使用System_Start方法,开始程序。 } hge->Texture_Free(tex);//释放纹理 delete spr;//释放精灵 hge->System_ShutDown();//程序停止 hge->Release();//释放HGE所占用的内存。 } |
编译运行代码后,是不是看到你指定的图片被显示在了屏幕上呢?很简单吧,游戏制作的第一步,就这样轻松的被我们迈了出去。
寰子的话:凌晨1:30了,累死我了,我才发现写教程不是最累的,最累的是排版……
HGE基础教程第三章:可以听到的--声音播放
HEFFECT:
这是HGE中的一个数据类型,就像HTEXTURE一样,但是它是用来保存载入的声音的,而HTEXTURE是用来载入保存的纹理(图像)的。我们根据以上的一章,知道了载入纹理是需要用Texture_Load函数的,那么,针对HEFFECT数据类型,也有一个函数用来专门载入声音。
Effect_Load函数
这是一个有返回值的函数,返回的值便是一个HEFFECT数据,于是,我们可以写:snd=Effect_Load("Source/music.mp3");
Effect_Free函数
这是一个没有返回值的函数,看函数的名字,Free,也就是释放了,那么这个函数不难理解,就是释放已经载入的声音数据,作用基本同于delete。
Effect_Play函数
这个函数的返回值是一个陌生数据类型,这个数据类型叫做HCHANNEL,什么意思呢?就是音轨的意思,我们知道,如果有5个同时播放而互不影响的音乐,那么,它们处在5个不同的音轨上。那么,这里也会返回一个音轨,方便我们来对这个音轨上播放的文件进行操作,诸如:“暂停,播放,继续,停止” 等。
实例代码:
以上简单列举了一下声音播放要接触到的几个基本函数,当然,我们首先让程序出声就可以了,随后再去考虑变调、变速、或者多轨混合等等这些东西。
代码: 写道: |
#include "hge.h" HGE *hge=0;//创建HGE指针 HEFFECT snd;//定义一个Effect(音效)对象 bool RenderFunc()//绘制函数,程序开始后HGE将不停调用它 { return false;//总是返回false } bool FrameFunc()//逻辑函数,程序开始后HGE将不停调用它,一些逻辑判断或者处理可以写在这里。 { if(hge->Input_GetKeyState(HGEK_A))//检测是否按下了A键 hge->Effect_Play(snd);//如果按下了A键,则播放音乐snd return false;//程序正常时总是返回false,返回true将从System_Start往下执行 } int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)//WinMain函数,程序的入口。 { hge=hgeCreate(HGE_VERSION);//使用hgeCreate函数创建HGE接口,参数必须传递正确的HGE_VERSION,它是在hge.h中定义的 hge->System_SetState(HGE_SCREENWIDTH, 800);//将屏幕宽度设置为800 hge->System_SetState(HGE_SCREENHEIGHT,600);//将屏幕高度设置为600 hge->System_SetState(HGE_FRAMEFUNC, FrameFunc);//设置逻辑函数为FrameFunc函数 hge->System_SetState(HGE_RENDERFUNC,RenderFunc);//设置绘制函数为RenderFunc函数 hge->System_SetState(HGE_TITLE, "播放声音");//设置窗口标题为“播放声音” hge->System_SetState(HGE_WINDOWED,true);//设置使用窗口模式 hge->System_SetState(HGE_USESOUND,true);//设置使用声音 if(hge->System_Initiate())//用hge类的System_Initiate()方法,检测初始化是否有错误出现。 { snd=hge->Effect_Load("声音路径和后缀,这里是相对目录,vc++2005是debug目录");//根据路径载入声音 if(snd)//检测声音是否已经载入成功 hge->System_Start();//如果没有问题,则使用System_Start方法,开始程序。 } hge->Effect_Free(snd);//释放声音资源 hge->System_ShutDown();//程序停止 hge->Release();//释放HGE所占用的内存。 } |
这基本就是最简单的声音播放了,根据以上学过的知识,我再写出几个需要注意的东西,第三章就结束了:
1:使用hgeSprite类,HTEXTURE,HEFFECT数据类型时,都不要忘记在不需要的时候或者程序结束的时候进行释放。
2:一定要在使用资源以前检测资源是否被载入,否则在使用资源操作函数时程序会出错退出。(如以上代码中的if(tex)....)
HGE基础教程第四章:显示顺序的仲裁者--Z-Buffer
Z-Buffer:
Z-Buffer又被称为深度缓冲,不要觉得深奥,我一一道破它的秘密。2D空间中,我们习惯了X,Y两轴的坐标,聪明的朋友可能一眼就知道Z是用来做什么的,没错,既然非要给2D空间安上一个Z坐标轴,那么它的作用,就是决定2D空间上的对象的前后顺序,前面的挡住后面的。有人说了:那直接改变绘制顺序不就好了,回答是:这样的程序是在编译时决定,而Z,是在运行时决定,这就意味着程序的灵活性将又有一个质的飞跃,你觉得哪个好呢?
开启2D空间中的第三根坐标轴:
不难发现,hgeSprite也好,hgeFont也好,都有一个方法:SetZ(float z);那么,可能有的朋友也试过,为啥不管用呢?可能你忽略了一步:打开Z-Buffer功能。如何打开呢?很简单,在开始的时候,使用加上以下一句:
hge->System_SetState(HGE_ZBUFFER,true);
这样,Z-Buffer的功能就被启用了。
Z-Buffer的范围:
Z-Buffer虽然是一个float,但是,它的有效范围只在0.0-1.0之间,至于为什么,我就不知道了,需要去问DirectX了,呵呵。在0.0-1.0这个范围内,Z值越小的对象,将被越靠前绘制,举个例子:
两个精灵,SpriteA,SpriteB,他们的Z值分别是0.1,0.2
这样的话,不管你render的顺序是什么,他们的覆盖顺序都是SpriteA覆盖SpriteB。
为什么要使用Z-Buffer:
本来我已经困了,打算明天再写,不过想了想,这节也没太多东西,一顺儿写完吧!
好,回归正题。除了刚才说到的“编译时决策”和“运行时决策”的问题,使用Z-Buffer又有一个好处,那就是它可以优化速度。拿刚才SpriteA和SpriteB的例子来说,
如果按我们的老思路,如果要A覆盖B,那么绘制的顺序是:RenderB,RenderA,由远及近,远处的先画,近处的后画,近处的覆盖远处的,就成了一个覆盖顺序正确的图像。那么,既然有了Z-Buffer,我么就要颠覆一下这套理论了,我们要先RenderA,再RenderB,为什么呢?因为当你 RenderA再RenderB的时候,DirectX会自己判断,有些地方已经有A的存在了,所以B就不需要在那些地方绘制东西了,直接跳过,小图不说,如果是两张满屏的大图呢?试想一下要节约多少FPS?这样的方法被称为逆向画家算法,但是,逆向画家算法也不是随便用的,必须要有Z-Buffer的支持,而且,最重要的是,Z-Buffer的顺序要设置正确,比如,A覆盖B,那么A的Z值要比B小,也就是更靠前一些,然后颠倒正常的绘制顺序,就达到了我们优化的目的。
说到这里,一定有人问了,能优化到什么程度呢?我说一下我的试验吧,一张800*600的满屏图,前面5000个50*100的动画小人不停走动,而且是每次都clear屏幕全部重绘的实时刷新,我是Geforce Go 7200的显卡,FPS达到了30+FPS。拿HGE带的例子比较,我在我的机器上试了,它的小人比我的小,到2000个的时候,就是30FPS,再往上就卡得要死了,当然,也是没有经过任何优化,这么以来,大家比一比,结果就出来了。
以上的东西我已经尽力写的很明白了,如果还有看不懂的就回帖提问吧!另外,毕竟我也是新手,老手勿笑!
HGE基础教程第五章:你需要知道的更多一些
hgeSprite的常用方法之--SetHotSpot:
Sprite,翻译过来是精灵,它是为我们来呈现texture的一个类,开始在图像显示的时候我也在代码里用到了这个类,这是我们在显示图像的时候经常用的东西,可能很多方法大家都不太了解,我现在说几个常用实用的。首先,我们知道,图像在屏幕上呈现的位置通常由一个坐标控制,这个坐标相对于屏幕左和上边缘,那么,相对于图像呢?可能有的人习惯认为图像的坐标相对于图像就是图像左上角的位置了,但是又有的人习惯把图像的中心作为这个决定位置的点,别怕,hgeSprite都会满足我们的要求,无论多么苛刻,那就是SetHotSpot方法,使用这个方法,你可以为你的精灵设置一个热点,这个热点,不仅仅决定了显示坐标相对于图像的位置,同时也决定了旋转时的中心,可谓是非常实用了。
hgeSprite的常用方法之--SetColor:
看名字就知道,是设置渲染色的,如果你设置一个红色的渲染色,那么,图像呈现出来就是带着红色渲染效果的,非常简单,设置的方法很简单,是一个 DWORD值,你可以理解为long,是这样的格式:0xFF00FF00,那么除去0x,前两位FF是透明度,这里是16进制,后面的6位分别是r, g,b,FF就相当于我们平时的255了。但是这样看起来可就太不方便了,那我们动用一下系统函数:ARGB(),传递给这个函数a,r,g,b,这4个参数,它就会反回一个相应的16进制数,那么,我们就可以这样些:SetColor(ARGB(alpha,r,g,b));这样看起来,是不是简单多了呢?好了,先说这么两个,说说其他。
如果我重新载入了Texture呢?
我们前面可以看到,hgeSprite是和HTEXTURE配套出现使用的,HTEXTURE是数据,而hgeSprite负责呈现它们,那么如果重新载入了图像呢?有的朋友会习惯性的学习new和delete使用时的方式,也就是要换,先调用hge->Texture_Free(tex) 来释放texture,然后再delete 精灵,其实是不用的,开始我也是这么写的,但是经过站长vicky_lh指点,我们这样写就可以:第一,在更换texture的时候你只需要tex= hge->Texture_Load(path)即可,不需要free,其次,精灵更不需要delete,只有在对象被卸载,或者程序结束的时候,才需要这么做。
程序可能出错,但是我想把错误写到我的文件里去
如果我们设置了logfile,那么hge会把所有的错误记录都会写到这个log里,如果我们有了自己的需要,那么如何截获hge发出的错误消息呢?使用这个方法:hge->System_GetErrorMessage(),它会返回一个char *,一个c风格字符串,里面就是程序到现在为止最后一条发生的错误信息。很方便吧?
我知道怎么播放音乐了,可是我该如何获取音乐的长度、暂停、继续等操作呢?
很简单啦,可能你也注意到了,有Channel_GetLength、Channel_IsPlaying等方法,可是怎么用呢?有朋友就问过我这个问题,我说一下如何解决,比如我们载入了一个HEFFECT数据,并且播放了它,那么,在使用hge->Effect_Play()方法的时候,它会反悔一个HCHANNEL数据,这个数据就是音轨数据,它返回了你这个音乐播放的音轨,我们要操纵这段音乐,就要靠音轨来操作,看代码片段(这是不能直接编译执行的,只是代码片段):
引用: |
HEFFECT snd;//声音数据 HCHANNEL channel; snd=hge->Effect_Load("音乐路径");//载入音乐数据 channel=hge->Effect_Play(snd);//播放音乐数据,并用channel将返回的音轨记录下来 hge->Channel_SetVolume(channel,"声音大小");//设置channel轨道声音的大小 //这样说,看起来就很简单了吧!呵呵,目的达到了! |
收尾:
本章没有多少东西,就是说了说一些小的大家不常常注意或者容易犯错误的地方,又熬夜写教程了,马上过年了,诸位新年快乐