<考古笔记>Hge游戏引擎(二)Core

考古笔记Hge游戏引擎(二)Core-编程之家


HgeCoreFunctions(Core Layer)


1.Hge.h的概要:

/*
概要(个人修改的内容已移除、修改字样标记)
*/
版本号:HGE_VERSION为BorlandC编译提供数学函数支持(不需要,已移除)基本数据类型:DWORD、WORD、BYTE句柄类型:HTEXTURE、HTARGET、HEFFECT、HMUSIC、HSTREAM、HCHANNEL导出dll的设置:EXPORT、CALL数学常量:M_PI32位色处理宏:ARGB、Set/GetA(R、G、B)融合方式选项:Color/Alpha/ZWriteInt设置:屏幕宽高、位深(bpp)、音效相关设置(采样频率、fx、music volume)、FpsString设置:标题名、图标名、ini/log文件名Bool设置:窗口/全屏,开启/关闭ZBuffer,开启/关闭TextureFilter、开启/关闭Sound、是否Suspend(挂起)、显示/隐藏鼠标、开启/关闭Splash(初始的Hge Logo动画)Func设置:FrameFunc、RenderFunc、FocusLost/GainFunc、GFXRestoreFunc、ExitFuncHwnd状态:HWND(普通)、HWNDPARENT(父窗口)电源状态控制(源码空定义,已移除)Fps状态:是否开启垂直同步(可移动至Bool设置)顶点格式:空间坐标(x,y)、depth(0..1)、color、纹理坐标(tx, ty)图元类型:线段、三角形、四边形(顶点数组、纹理贴图句柄、blend方式)Input事件:事件类型(KeyDown/Up, MButtonDown/Up, MouseMove/Wheel)、Key码,Flags(Shift, Ctrl, Alt, Capslock, ScrollLock, NumLock, Repeat),键盘按键(ascii码)/鼠标滚轮/鼠标位置(x, y)外部接口--纯虚类HgehgeCreate全局C接口声明虚拟键值(Virtual Key Cod

2.Hge启动流程

通过全局的C函数hgeCreate(C++因为提供函数重载,生成的接口函数名会带有@数字/字符(详见名称重整技术,hge.def文件也是用于解决这个问题的))获取Hge接口,__stdcall作用为让函数调用方负责清栈,在使用完Hge接口后调用Release来释放Hge接口(使用了引用计数技术,Release开销很小)。

hgeCreate实际工作是new一个Hge_Impl类(public继承于Hge类),并向上转型为Hge*返回。

获得Hge接口后自行设置一系列Bool、Int、Func、String状态/开关,然后再使用System_Initiate初始化,初始化过程中Hge会获取系统当前时间、Hge版本、操作系统版本、物理/虚拟内存情况,写入到log文件中,再注册窗口类、创建窗口、初始化Timer、Random、Input、Graphics(GFX)、Sound这些子系统,最后根据是否定义DEMO宏来播放Splash动画。

Hge_Impl下除了System之外,有Resource、Ini、Random、Timer、Sound(Effect, Music, Stream, Channel)、Input、Graphics(GFX)子系统。值得一提的是,子系统的所有成员变量以及方法全部都放在Hge_Impl类中,以良好的函数命名以及注释来划分。
考古笔记Hge游戏引擎(二)Core-编程之家

System_Initiate结束之后使用System_Start来执行消息循环。

在收到结束消息,退出循环后使用System_Shutdown关闭各个子系统,最后再使用Release释放Hge接口。


3.子系统简介

Random

值得一提的是随机数种子定义的是全局变量,这一点我觉得不如封装成Singleton类,种子为静态变量。

/*
Random概要
*/unsigned int g_seed=0;// 随机数种子的获取
// 初始化时Random_Seed(0);
void CALL HGE_Impl::Random_Seed(int seed)
{if(!seed) g_seed=timeGetTime();else g_seed=seed;
}// 获取随机的int数
int CALL HGE_Impl::Random_Int(int min, int max)
{g_seed=214013*g_seed+2531011;return min+(g_seed ^ g_seed>>15)%(max-min+1);
}// 获取随机的float数
float CALL HGE_Impl::Random_Float(float min, float max)
{g_seed=214013*g_seed+2531011;//return min+g_seed*(1.0f/4294967295.0f)*(max-min);return min+(g_seed>>16)*(1.0f/65535.0f)*(max-min);
}

Demo

实现方式是将FrameFunc先设置为Demo.cpp中定义的DFrame(RenderFunc设为0,因为DFrame将Render的工作也写在了一起),贴一张Hge Logo图(数据在Demo.cpp的hgelogo数组中)到屏幕中心并根据时间修改其alpha值。

/*
splash screen animation
*/  dtime+=pHGE->Timer_GetDelta();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);

Timer

    //  计时器精度由初始化时timeBeginPeriod(1)设置为1ms//  其他数值初始化如下//  fTime=0.0f;//  t0=t0fps=timeGetTime();//  dt=cfps=0;//  nFPS=0;float               fTime; // 当前时间,可由Timer_GetTime获取float               fDeltaTime; // 帧之间的时间间隔,可由Timer_GetDelta获取DWORD               nFixedDelta;int                 nFPS;  // Fps值,可由Timer_GetFPS获取DWORD               t0, t0fps, dt;int                 cfps;

Log、Ini

log文件写入是通过va_list可变长参数和vfprintf实现的:

void CALL HGE_Impl::System_Log(const char *szFormat, ...)
{FILE *hf = NULL;va_list ap;if(!szLogFile[0]) return;hf = fopen(szLogFile, "a");if(!hf) return;va_start(ap, szFormat);vfprintf(hf, szFormat, ap);va_end(ap);fprintf(hf, "n");fclose(hf);
}

Ini文件用于保存本次程序运行的设置参数,使得在下一次程序执行时可直接读取这些参数。
Ini.cpp提供了对int、float、string三种类型参数的写入/读取支持,利用的是Get/WritePrivateProfileString函数。
实际上我觉得可以用lua这样的脚本语言来做配置参数表,自己封装Lua与C/C++交互的工具类,开源的库也有LuaBind。


Sound

// 音频的数据流使用单链表
struct CStreamList
{HSTREAM             hstream;void*               data;CStreamList*        next;
};

Sound系统封装了Bass库,支持了采样频率、多声道等高级效果。


Resource

struct CResourceList
{char                filename[_MAX_PATH];char                password[64];CResourceList*      next;
};

Resource系统封装了Zlib库,支持解压打包好的加密/不加密资源包,使用简单的单链表一一读取需要的资源。


Input

struct CInputEventList
{hgeInputEvent       event;CInputEventList*    next;
};

鼠标/键盘输入的事件由单链表实现的队列管理。


Graphics

Gfx封装了DirectX8的API。

Texture
struct CTextureList
{HTEXTURE            tex;int                 width;int                 height;CTextureList*       next;
};

Target
struct CRenderTargetList
{int                 width;int                 height;IDirect3DTexture8*  pTex;IDirect3DSurface8*  pDepth;CRenderTargetList*  next;
};