Lua小记

No Comments

      因工作关系,花了几天时间学习了下Lua,对其基本语法、和C/C++的交互有一个初步的了解。

     因之前有看过Python,所以熟悉Lua没有花多少精力,可以去官网看手册,网上也可以找到大把免费电子书,包括中文的。去官网下载的最新安装包,安装后发现有一个工具软件”SciTE”挺好用,至少在学习阶段跑跑测试用例足够了。如果喜欢用VS编辑,可以考虑安装一个VS插件Google了一个http://vslua.codeplex.com/ 还有其他的),虽然可以通过若干种方法使用VS编译Lua文件1.VS2005开始被支持的自定义编译规则、2.“工具”->“外部工具”),不过没发现一个好的调试办法,也无法运行之,所以放弃了。尝试使用Eclipse,不过杯具的是那个插件(http://luaeclipse.luaforge.net/ )居然无法安装!

     和很多人一样,我学习Lua之意并不在于其本身,更多的是它的C++扩展。包括在C++中使用Lua脚本和使用C++扩展Lua库。这在游戏领域和UI领域用得特别广泛。著名的跨平台UIWxWidget就有Lua扩展WxLuahttp://wxlua.sourceforge.net/ )。游戏UICEGUI也默认支持Lua

     在C++中调用Lua脚本的应用相对少见,更多的时候是使用C++来扩展Lua库。对于后者有不少成熟的封装库可以使用,例如tolua++luabindcpplua等,而在C++中调用Lua一般直接使用lua C API来实现。

     用C++扩展Lua库有两种情况,一种是提供封装库文件(一般是.dll.so文件),在这种情况下,Lua程序员可以用Lua完成全部功能,前面提到的WxLuaWxWidget貌似被很多语言河蟹了一遍,包括WxPythonWxLuawxRuby wxErlang wxPerl 就是这种情况。

     有时候在一个特定项目中,我们只需要将部分功能的实现从C++转移到Lua。这在游戏开发中特别常见,这样可以让一些非程序开发人员(例如策划、美工)来完成最繁琐的业务逻辑开发工作。此时一般不提供独立的Lua库文件,而是在一个C++静态库或者C++程序内部实现之。在C++程序调用基于该库的Lua脚本前先动态加载该库。这种处理方法实际上用到了两个方向的Lua C API。这样处理有更好的安全性,因为暴露给Lua的接口必须通过一个特定程序才能加载。

HGE引擎学习笔记-UI

No Comments

1.窗口消息

      尽管HGE的UI框架(下面以HGEUI称呼之)和当前主流的UI框架比起来还很简陋,不过麻雀虽小,五脏俱全,所以打算以一个通用UI框架的视角来观察之。

      研究一个UI框架,首先得从最重要的窗口消息处理入手。HGEUI的窗口消息和HGE的消息混在一起,所以就先看看HGE消息入手。

    1.1.HGE窗口消息

      HGE通过Input接口来提供消息的访问,这种方式不是Windows默认的触发性消息,而是轮询方式。程序如果需要用到窗口消息,自己去查询。具体的API见【hge.h/input.cpp】的下列成员函数:

virtual void	CALL	Input_GetMousePos(float *x, float *y) = 0;
virtual void	CALL	Input_SetMousePos(float x, float y) = 0;
virtual int	CALL	Input_GetMouseWheel() = 0;
virtual bool	CALL	Input_IsMouseOver() = 0;
virtual bool	CALL	Input_KeyDown(int key) = 0;
virtual bool	CALL	Input_KeyUp(int key) = 0;
virtual bool	CALL	Input_GetKeyState(int key) = 0;
virtual char*	CALL	Input_GetKeyName(int key) = 0;
virtual int	CALL	Input_GetKey() = 0;
virtual int	CALL	Input_GetChar() = 0;
virtual bool	CALL	Input_GetEvent(hgeInputEvent *event) = 0;
 

      这些函数都是查询函数,查询数据来自该类的成员变量,这些变量会随着Windows窗口消息的触发而动态更新。这些更新操作通过几个函数实现。

  1. _UpdateMouse:该函数在HGE主循环中被调用,主要更新鼠标是否在当前窗口上

  2. _BuildEvent :该函数在Windows窗口回调中被调用,更新其他窗口消息相关的变量。见system.cpp中的WindowProc函数。

    1.2.HGEUI窗口消息

      HGEUI继承了它老爹的优良传统,同样不使用触发式消息系统,而是让底层调用它的相关函数来更新自己的状态和完成绘制。在这些函数里面通过上述的函数获得窗口消息,然后更新自己。

2.Ui绘制

      HGEUI中的绘制很简单,就是通过HGE对DX封装的那一套东西画画图。

3.光标

      如果仔细观察可能会发现,HGE默认没有光标,不过可以通过设置HGE_HIDEMOUSE标志来激活光标。不过鉴于游戏一般都使用自定义光标,所以激活这个选项意义不大。

      HGE中的自定义光标在hgeGUI中被支持。可以通过hgeGUI类的SetCursor函数设置光标图片。

4.焦点

      如果仔细看源码,会发现HGE有焦点的代码,而GUI这边又有焦点相关的代码,实际上这两者不一样,前者关于窗口焦点,后者关于控件焦点。如果不懂相关概念,见这里【http://www.ibm.com/developerworks/cn/linux/l-cn-focus/index.html 】。

      作为一条不成文的规矩,控件焦点可以通过Tab键导航,不过貌似HGEUI并没有遵守这个规矩。不过它提供其他的焦点导航方式:

  1. HGEGUI_NONAVKEYS :无键盘导航

  2. HGEGUI_LEFTRIGHT :左右按键导航

  3. HGEGUI_UPDOWN :上下按键导航

  4. HGEGUI_CYCLED :循环

      焦点链【保存当前控件上/下一个焦点控件的数据结构】通过hgeGUIObject类的next和prev指针实现。这两个指针在hgeGUI类的AddCtrl函数中被初始化。所以HGEUI的焦点链和AddCtrl的顺序是一致的。可以通过hgeGUI类的SetFocus来强制特定控件获得焦点。当前获得焦点的控件存储在hgeGUI类中的ctrlFocus指针中。

      除了获得焦点的控件外,还有一个特别的控件,即鼠标所在的窗口(Hover)。一般情况下,键盘消息经过HGE那一层处理和过滤后,会直接送到获得焦点的控件,不过鼠标消息则不定,鼠标按下消息就会送到鼠标所在的窗口,例如单击事件。这个控件存储在hgeGUI类中的ctrlOver指针中。

      HGEUI通过比较当前鼠标坐标和控件区域来更新这个指针。

 

5.控件

      千万不要跟我说找不到HGEUI控件的Windows窗口句柄。

      HGEUI的控件必须继承自hgeGUIObject,该函数包含一个纯虚函数Render,所以必须实现之,不过还有一个重要的函数有必要实现,Update函数。这两个函数一起完成控件的绘制,Render函数完成具体的绘制操作(渲染),可以认为是普通UI模型中的Paint函数,而Update做一些渲染前的准备,可以认为是普通UI模型中的Layout函数。个人觉得这两个函数和HGE模型中的两个系统回调类似,RenderFunc 回调匹配Render函数,FrameFunc回调匹配Update函数。

    5.1.控件初始化和终止

      在HGEUI中包含一个普通UI框架少见的feature,即Enter和Leave。即控件初始化和终止时的特殊处理支持。这样当控件第一次被绘制和最后退出时可以有特殊的表现,例如开始动画和终止动画。这个操作通过hgeGUIObject类的Enter和Leave函数来实现。

      那HGE怎么知道控件是否初始化/终止完了呢?通过hgeGUIObject类的IsDone函数返回值,如果返回true则表示已经结束。该函数默认总是返回true,表示随时可以被河蟹。

    5.2.控件消息

      控件除了将UI渲染分离成多个子模块实现外,最重要的功能就是用户交互。那HGEUI怎么接收和处理窗口消息呢?继承hgeGUIObject类的下列虚函数:

virtual bool	MouseMove(float x, float y) { return false; }
virtual bool	MouseLButton(bool bDown) { return false; }
virtual bool	MouseRButton(bool bDown) { return false; }
virtual bool	MouseWheel(int nNotches) { return false; }
virtual bool	KeyClick(int key, int chr) { return false; }

 

      此外处理键盘鼠标消息外,HGEUI控件还可以响应Focus事件,见hgeGUIObject类的虚函数:

virtual void	Focus(bool bFocused) {}

 

    5.3.消息回调

      控件响应消息除了更新自己外,更多的是做逻辑处理。最简单的方法就是将逻辑处理代码写到窗口消息回调函数里面,不过这样有一个致命的缺陷,控件毫无移植性。一般的做法是控件提供接口来注册回调,当收到相关窗口消息后调用该回调。或者将所有控件的逻辑处理重定向到某一个位置,通过一个ID(一般用控件ID)来区分不同的控件源。

      HGE使用后者,不过仅仅对鼠标消息有效,而且实现很诡异。见hgeGUI的ProcessCtrl函数。如果该类的bLPressed属性被设置,它会返回该控件的ID。可以参考官方源码sample6。

 

      在这里【http://blog.csdn.net/ShowLong/archive/2007/07/02/1675197.aspx】有一个关于HGE中文输入控件的实现,可以借鉴一下。

HGE引擎学习笔记-字体

4 Comments

1.精灵

      精灵(hgeSprite)是HgeHelper中实现的一个用得非常多的类,很多更高级的模块也基于该类,包括字体,所以在详细阐述字体之前,先说说它。

      hgeSprite对纹理渲染进行简单的封装,它通过一个纹理句柄和区域参数进行初始化,不过底层的渲染参数仍旧基于hgeQuad,见hgeSprite 下列成员函数:

void	Render(float x, float y);
void	RenderEx(float x, float y, float rot,
		float hscale=1.0f, float vscale=0.0f);
void	RenderStretch(float x1, float y1, float x2, float y2);
void	Render4V(float x0, float y0, float x1, float y1,
		float x2, float y2, float x3, float y3);
 

      hgeSprite提供了更为丰富的属性Get/Set,以及更为高级的渲染方式。包括对纹理按比率放缩,旋转,任意矩形放缩和任意四边形放缩。

 

2.字体

      字体(hgeFont)实现基于 hgeSprite,和普通的UI字体不同,HGE中字体实际上是贴图,而这些图片这通过HGE自定义的字体文件提供,后缀为fnt,可以通过HGE官方提供的工具生成。

2.1.字体使用

      HGE字体使用相对简单,不过和其他很多游戏库一样,中文支持是个麻烦。默认的用法如下:

//创建字体对象
HgeFont* fnt=new hgeFont("font1.fnt");
//绘制字体
fnt->printf(5, 5, HGETEXT_LEFT,
	"dt:%.3f\nFPS:%d (constant)",
	hge->Timer_GetDelta(),
	hge->Timer_GetFPS());
//销毁字体对象
delete fnt

      当然在printf之前,也可以设置很多常用的字体参数,如颜色、大小、字距、alpha等。不过不支持字体,所以如果希望使用多个字体,可以定义多个字体文件,并且分配多个 hgeFont实例。详细的字体参数配置见 hgeFont类。

2.2.字体定义

      HGE一个字体包含两部分,一个字体配置文件(.fnt),另一个是字体字模文件(.png)。之所以使用png可能是该格式支持alpha通道吧。

      fnt文件定义了匹配的字模图片文件,以及每一个字符所占用的区域。一个典型的英文字体配置如下:

[HGEFONT]

Bitmap=font1.png

Char=” “,0,0,8,27,0,0

Char=”!”,8,0,5,27,0,0

Char=”"”,13,0,9,27,0,0

Char=”#”,22,0,13,27,0,0

      很显然这种“字体”和点阵字体差不多,所以如果放缩太多容易造成马赛克或者走样。

2.3.字体渲染

      前面提到, hgeFont基于 hgeSprite。实际上,渲染字体就是根据字符序列获得匹配的字模,然后做变换(放缩、旋转等)、Layout,最后通过 hgeSprite来渲染。

      hgeFont使用成员 hTexture存储纹理句柄,而成员letters[256]则存储“256”个字符。这些成员在构造函数中被初始化。具体的渲染操作在函数hgeFont::Render中实现,在那里还包含简单的Layout。

2.4.中文支持

      现在网上有很多牛人提供了中文支持解决方案。说起来中文支持原理很简单,不过很多细节很难把握。

      因为HGE字体渲染使用“点阵字模”,所以自动生成一张包含中文的字模就可以了。不过有几个问题:

  1. 汉字不和ascii码一样就那么几个(我是不知道确切有多少个汉字的),所以如果把所以汉字都贴出来会不会很大,效率会不会受影响,一张图片能不能容得下。而如果只保留常见字,那这个“度”怎么把握?

  2. ascii的索引非常方便,而且效率非常高,可是中文首先字符编码有多种,有些字符编码还是变长,所以对字符作一个好的索引比较麻烦。特别是只取部分汉字时。

  3. 正因为汉字特别多,所以必须有一个自动化的工具生成字模图。

      当然HGE默认的字体渲染框架对于中文并不一定是最合适的,我们完全可以对其源码做适当的修改(甚至重写)已获得更高的性能。

HGE引擎学习笔记-基础篇

No Comments

1.Sample

1.1.Hello world

       具体可以参考HGE官方源码包中的sample1【hge_tut01】

#include "hge.h"
HGE *hge = 0;
bool FrameFunc()
{
	if (hge->Input_GetKeyState(HGEK_ESCAPE)) return true;
	return false;
}
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
	hge = hgeCreate(HGE_VERSION);
	hge->System_SetState(HGE_FRAMEFUNC, FrameFunc);
	hge->System_SetState(HGE_TITLE, "HGE Tutorial 01 - 
                            Minimal HGE application");
	hge->System_SetState(HGE_WINDOWED, true);
	hge->System_SetState(HGE_USESOUND, false);
	if(hge->System_Initiate())
	{
		hge->System_Start();
	}
	hge->System_Shutdown();
	hge->Release();

	return 0;
}

       为了保持简单,去除了注释和错误处理

       HGE程序要点:

  1. 创建HGE结构,并获得句柄(指针)

  2. 设置该句柄的相关参数,其中重要的参数包括

    1. HGE_FRAMEFUNC :设置帧回调函数

    2. HGE_RENDERFUNC :设置渲染回调函数

    3. HGE_SCREENWIDTH :设置窗口宽

    4. HGE_SCREENHEIGHT :设置窗口高

    5. HGE_WINDOWED :设置窗口模式(是否全屏)

    6. HGE_TITLE :设置窗口标题

    7. HGE_FPS :设置fps上线

    8. HGE_LOGFILE :设置日志文件名称

  3. 初始化HGE结构

  4. 加载其他资源和其他初始化工作(上面的程序没有)

  5. 启动主循环,正式进入运行状态

  6. 释放、回收资源

       上面的程序很简单,仅仅启动一个窗口(屏幕全黑),并且在玩家按下Esc键后退出。

 

1.2.帧回调函数

       帧回调函数(FrameFunc)执行一些渲染初始化的工作,特别是Layout,消息也在这里被处理。该函数返回true将导致消息循环退出。

       一般情况下,该函数内的处理流程是:

  1. 获取、分析窗口(和控件)消息

  2. 判断是否退出

  3. 根据窗口消息来决定渲染的行为(例如渲染的位置、控件的状态等)

1.3.渲染回调函数

       渲染回调函数(RenderFunc)执行具体的渲染工作。如果无需渲染,可不需要,如上面的程序。

 

2.HGE总体架构

        HGE包含三个大的模块,包括两个程序模块和一个工具模块。两个程序模块分别以程序工程的形式提供。所以如果需要使用HGE,需要连接上述两个工程产生的库文件。分别是HgeCore和HgeHelper。

       HgeCore是整个HGE引擎的基础,它是HgeHelper的基础,主要实现一个基本功能的封装。HgeHelper基于HgeCore开发,实现了一些更为复杂的操作,方便游戏开发者。这个模块是游戏开发者最常打交道的部分。不过如果觉得HgeHelper太烂或者无法满足需求,完全可以基于HgeCore自写一个HgeHelper。当然也可以自写HgeCore,不过这跟重新弄个引擎就没啥区别了。

       工具模块主要包含一些资源生成相关的工具,例如字体、粒子系统配置的生成。

 

3.HgeCore

        对Win Gui、Dx8以及相关第三方库的一个简单封装,具体内容:

  1. 图片纹理支持,包括bmp、jpg、png等主流格式支持,底层使用DX8。

  2. 音频支持(OSS库)

  3. 窗口消息支持(输入设备,鼠标、键盘)

  4. 窗口模式支持(全屏和窗口)

  5. 资源支持(Zip文件)

  6. 日志支持

  7. 配置文件支持(.ini)

3.1.程序结构

       HGE将上述所有接口都定义在【include\hge.h】,在这里HGE定义一个虚基类。具体的实现定义在子类HGE_Impl中【core\hge_impl.h】。而该类的实现则分别在

  1. graphics.cpp :纹理贴图支持

  2. ini.cpp :ini文件支持

  3. input.cpp :窗口消息支持

  4. random.cpp :随机数支持

  5. resource.cpp :资源支持(zip)

  6. sound.cpp :音频支持

  7. timer.cpp :时间相关支持

  8. system.cpp :系统支持,包括初始化、终止、消息循环以及配置等。

 

4.基本操作

4.1.音效

       HGE音效使用BASS库【http://www.un4seen.com/ 】,使用非常简单,见下列几个API:

//加载和释放音效
HEFFECT snd=hge->Effect_Load("menu.wav");
hge->Effect_Free(snd);
//播放
hge->Effect_Play(snd);
hge->Effect_PlayEx(snd,100,pan,pitch);

 

4.2.窗口消息

       获得窗口消息很简单,见hge.h中的Input系列函数,例如判断是否按下Esc键可以使用如下代码:

if (hge->Input_GetKeyState(HGEK_ESCAPE))

       HGE每一次刷新都会轮询当前的输入情况,具体见函数System.cpp中的窗口回调WindowProc以及HGE_Impl::System_Start()中的主循环实现。HGE会将上次的窗口消息保存起来,以供接下来的查询。

4.3.纹理渲染

       HGE中可以渲染矩形和三角形(这里不阐述)。分别通过结构hgeQuad和hgeTriple来存储渲染信息。渲染底层实现使用DX8,理论上可以移植到DX后续版本或者OpenGL。

       HgeQuad贴图包含三个部分:

  1. 纹理句柄,纹理可以从主流的图片格式中获取,例如jpg、png、bmp等。

  2. 渲染位置,由四个点组成,顺序依次是左上、右上、右下、坐下。如果纹理大小和渲染位置不一致,纹理将被拉伸(或缩小)以切合渲染位置大小。大小使用像素作为单位。

  3. 纹理区域,同样包含四个点,不过和“渲染位置”不同的是它使用比率作为单位,例如【(0,0)、(1,0)、(1,1)、(0,1)】表示使用整个纹理区域。很显然,如果想使用左上角1/4区域,可以使用【(0,0)、(0.5,0)、(0.5,0.5)、(0,0.5)】。

       关于纹理渲染,建议参考HGE官方sample2【hge_tut02】,如果看过官方sample6【hge_tut06】,可能会疑问,怎么实现平铺效果,背景图的动态平移又怎么实现呢?修改HgeQuad中的纹理区域可以做到。实际上,任何一张纹理在HgeQuad中就是一个由该纹理一张挨一张的平铺平面,所以我们只要稍微计算一下大小即可平铺。

       例如纹理大小为(W,H),而渲染区域是(W1,H1)。我们将纹理区域设置为【(0,0)、(W1/W,0)、(W1/W,H1/H)、(0,H1/H)】即可。而如果需要实现动态平移,可以设置两个变量(X,Y),将【(X,Y)、(X+W1/W,Y)、(X+W1/W,Y+H1/H)、(X,Y+H1/H)】。其中X,Y分别表示平移的比率,例如需要向上平移,就可以将X根据时间不断增大(超过纹理大小置零)。

       很显然,如果想使用句柄纹理来平铺,上述方法无法实现。

       关于渲染众多参数的说明,可以参考下这里【http://blog.csdn.net/wenzhoufeng22/archive/2008/04/22/2316016.aspx

 

 

5.时间控制

        时间控制主要包括三个方面:

  1. 运行总时间

  2. 上次刷新间隔

  3. fps控制

       时间控制相关的变量,见类HGE_Impl成员

	float				fTime;
	float				fDeltaTime;
	DWORD				nFixedDelta;
	int				nFPS;
	DWORD				t0, t0fps, dt;
	int				cfps;

	int				nHGEFPS;
  1. nHGEFPS :设定的最高fps,默认为不设置,即0

  2. nFixedDelta :两次刷新的最小时间间隔,默认为0,更新nHGEFPS时会同时更新它。

  3. t0 :上次刷新的时间戳(ms)

  4. t0fps :统计fps的初始时间戳,如果间隔超过1s,该值被复位

  5. dt :本次刷新和上次刷新的间隔(ms)

  6. fDeltaTime :本次刷新和上次刷新的间隔(s)

  7. fTime :自启动后已经运行的时间(s)

  8. cfps :统计fps的计数器,在1s内,每刷新一次该值加一

  9. nFPS :fps,当统计fps间隔超过1s后,该值被复制为cfps

       上述两个变量可通过下面三个成员获得:

	virtual float		CALL	Timer_GetTime();
	virtual float		CALL	Timer_GetDelta();
	virtual int			CALL	Timer_GetFPS();

       而设置FPS上线,则通过设置选项来完成:

	hge->System_SetState(HGE_FPS, X);

 

5.1.时间计数

       在循环启动和每一次刷新后,HGE会保存当前时间作为“上次运行时间”。等到下次刷新开始前会用当前时间减去“上次运行时间”来获得“上次刷新间隔”,同时一个会将该值累加到“运行总时间”变量中。

5.2.Fps计数

       HGE保存一个计数器C1,初始值为循环启动时间。每次刷新,会用当前时间减去该值。如果小于1000(ms),则将一个临时FPS计数器C2加1(初始值为0)。否则将C1赋值为当前时间,并且将C2赋值到FPS正式计数器(可以通过 Timer_GetFPS函数访问)然后将C2清零。

5.3.Fps限制

       HGE默认设置最高的FPS是1000,因为在HGE_Impl::System_Start() 中有如下显示:

	do { dt=timeGetTime() - t0; } while(dt < 1);

       两次刷新必须要大于1ms。不过程序员可以通过设置相关参数设置更低的Fps上限。当设置上限后,Hge会更新变量 nFixedDelta。然后在HGE_Impl::System_Start() 函数中判断是否低于这个时间阀值,如果低于这个阀值,就跳过刷新。

	if(dt >= nFixedDelta){
      		//刷新操作

 

 

6.HGE logo

              HGE提供的sample中启动时总是会出现一个启动图标,如下:

aaaxxxx

 

       如果不希望显示,可以在初始化之前通过设置下面的标志位取消

	HGE.System_SetState(HGE_SHOWSPLASH, false) 

       而如果希望从源码中去掉这些代码实现,可以Undef DEMO宏。具体的实现在【core/demo.cpp】。调用代码如下【HGE_Impl::System_SetStateInt函数】:

	if(pHGE->bDMO)
	{......
		DInit();
		pHGE->System_Start();
		Ddone();
               ......
	}

 

6.1.Demo渲染

       具体的实现很简单,如下:

	if(dtime<0.25) alpha=(BYTE)((dtime*4)*0xFF);
	else if(dtime<1.0) alpha=0xFF;
	else if(dtime<1.25) alpha=(BYTE)((1.0f-(dtime-1.0f)*4)*0xFF);
	else return true;

       一共持续1.25s,在前0.25s将alpha通道从0递增到1,到1.0s时保持1不变,而到1.25s时又慢慢地从1递减到0。超过1.25s后返回true退出循环。从而实现一个logo慢慢显示而后又慢慢消失的效果。

 

几个不错的blog,排名不分先后

http://hi.baidu.com/%B3%FE%D3%CE%D6%D0%D0%C4/blog/category/hge%D1%A7%CF%B0/index/1

http://yoyo.is-programmer.com/categories/3035/posts?page=4

http://blog.csdn.net/wenzhoufeng22/archive/2008/04/22/2316002.aspx

http://blog.csdn.net/ShowLong/category/316668.aspx

开始玩HGE

No Comments

      经高人指点,选择开源2D游戏引擎HGE【http://hge.relishgames.com】作为涉足游戏开发的切入点。

      第一件事自然是下载源码,然后在本地编译。见这里【http://hge.relishgames.com/files/hge17.zip 】。之所以选择1.7而不是选择最新的1.8是因为编译1.8在我本地会出错(貌似不止我),如下:

1> Creating library ..\..\lib\vc\hge.lib and object ..\..\lib\vc\hge.exp

1>system.obj : error LNK2019: unresolved external symbol "public: void __thiscall HGE_Impl::_InitPowerStatus(void)" (?_InitPowerStatus@HGE_Impl@@QAEXXZ) referenced in function "public: virtual bool __stdcall HGE_Impl::System_Initiate(void)" (?System_Initiate@HGE_Impl@@UAG_NXZ)

1>system.obj : error LNK2019: unresolved external symbol "public: void __thiscall HGE_Impl::_DonePowerStatus(void)" (?_DonePowerStatus@HGE_Impl@@QAEXXZ) referenced in function "public: virtual void __stdcall HGE_Impl::System_Shutdown(void)" (?System_Shutdown@HGE_Impl@@UAGXXZ)

1>system.obj : error LNK2019: unresolved external symbol "public: void __thiscall HGE_Impl::_UpdatePowerStatus(void)" (?_UpdatePowerStatus@HGE_Impl@@QAEXXZ) referenced in function "public: virtual bool __stdcall HGE_Impl::System_Start(void)" (?System_Start@HGE_Impl@@UAG_NXZ)

1>..\..\hge.dll : fatal error LNK1120: 3 unresolved externals

      这里【http://www.hgechina.com/forum/viewtopic.php?start=0&p=191&topic_view=0&sid=271f494ec860de6ee5aafb5846ae4e0f 】有讲到编译时的一系列问题。

      HGE官方版使用DX8,所以为了成功编译需要安装DX8或者下载其头文件和lib。我选择后者,下载见这里【http://resource.gameres.com/dx81.zip】,因为不想装太多东西,况且Win 7也不一定支持那么老掉牙的东东。

      源码中需要编译的项目主要是【src/core】和【src/helpers】,不过编译前者又出错了,如下:

1>c:\program files\microsoft sdks\windows\v6.0a\include\winnt.h(236) : error C2146: syntax error : missing ‘;’ before identifier ‘PVOID64′

1>c:\program files\microsoft sdks\windows\v6.0a\include\winnt.h(236) : error C4430: missing type specifier – int assumed. Note: C++ does not support default-int

1>c:\program files\microsoft sdks\windows\v6.0a\include\winnt.h(7818) : error C2146: syntax error : missing ‘;’ before identifier ‘Buffer’

1>c:\program files\microsoft sdks\windows\v6.0a\include\winnt.h(7818) : error C4430: missing type specifier – int assumed. Note: C++ does not support default-int

1>c:\program files\microsoft sdks\windows\v6.0a\include\winnt.h(7818) : error C4430: missing type specifier – int assumed. Note: C++ does not support default-int

     

      于是将DX8的路径直接插到Include Path最前面,让程序编译时使用DX8中的winnt.h。问题解决(注意:为了不影响其他程序编译,建议在编译成功后将此次更改还原),如下:

aaa

      最后又出现下面的错误,直接将其加入Ignore Specific Library解决问题!

1>Linking…

1>LINK : fatal error LNK1104: cannot open file ‘libci.lib’

      为了调试方便,将两个项目的“Configuration Type"由Dll改为Lib

      Hge源码包中包含若干sample(tutorials】目录),所以下一步就是将这些代码并到同一个Solution中。

      Done!!!