原帖地址:http://blog.csdn.net/i_dovelemon/article/details/8818037
另外,年代久遠,該引擎官網早已上不去了!!!
1.庫的安裝和下載
從官網上http://hge.relishgames.com/上可以下載到最新的HGE游戲引擎,此游戲引擎是完全免費開源的。在此感謝此引擎的編寫者,感謝他的無私奉獻。本教程是入門的教程,可是在此也並不介紹如何配置環境,這些操作網上琳琅滿目,讀者可自行上網收索
2.HGE實例
#include<hge.h>
#pragma comment(lib,"hge.lib")
Q:為什么要導入這個lib?不是在配置里面添加了嗎?
A:由於不可知的原因,在VC6.0中配置時,加入了lib之后,所有其他的函數都可以使用,只有hgeCreate函數總是提示“無法解析的外部符號”。而這個函數是創建HE游戲引擎的函數,可謂是巨頭函數,這個函數不能用,那整個程序就Game Over了。所以在用代碼導入這個lib之后,就可以使用了。
//定義全局變量
HGE * hge = NULL ;
hgeQuad quad ; //用於保存繪圖的頂點,紋理,和混色的函數
Q:hgeQuad結構是什么?
A:查看HEG的官網,上面解釋說這個結構是跟繪圖有關的結構。如果要繪圖,就需要有這個結構存在。以下是這個結構的詳細定義:
struct hgeQuad
{
hgeVertex v[4] ;
HTEXTURE tex ;
int blend ;
};
上面結構中的幾個成員分別是hgeVertex頂點結構,用於保存頂點的信息;第二個是HTEXTURE結構的數據,此結構是紋理的句柄;blend表示混色模式。
HEFFECT snd ; //保存音效的句柄
float x = 100.0f , y = 100.0f ;
float dx = 0.0f , dy = 0.0f ;
const float speed = 90 ;
const float friction = 0.98f ;
//定義播放音效的函數
void boom()
{
int pan = int((x-400)/4);
float pitch = (dx*dx+dy*dy)*0.0005f + 0.2f ;
hge->Effect_PlayEx(snd,100,pan,pitch); //snd是音頻資源的句柄,100表示聲音大小,pan表示左右聲道,pitch表示播放頻率
}
Q:Effect_PlayEx函數是什么用處?
A:Effect_PlayEx函數,用於播放指定的音效文件,同時可以根據后面的幾個參數來進行聲音,聲道,播放頻率的改變。
//定義幀回調函數
bool FrameFunc()
{
float dt = hge->Timer_GetDelta(); //獲取自上次調用此函數到此次調用此函數的時間間隔
if(hge->Input_GetKeyState(HGEK_ESCAPE))
return true ;
//根據不同的按鍵,使用速度和延遲時間來修正位置
if(hge->Input_GetKeyState(HGEK_LEFT))
dx-=speed*dt ;
if(hge->Input_GetKeyState(HGEK_RIGHT))
dx+=speed*dt ;
if(hge->Input_GetKeyState(HGEK_UP))
dy-=speed*dt ;
if(hge->Input_GetKeyState(HGEK_DOWN))
dy+=speed*dt ;
//做一些運動的計算
dx*=friction;
dy*=friction;
x+=dx;
y+=dy;
if(x>784)
{
x=784-(x-784);
dx=-dx;
boom();
}
if(x<16)
{
x=16+16-x;
dx=-dx;
boom();
}
if(y>584)
{
y=584-(y-584);
dy=-dy;
boom();
}
if(y<16)
{
y=16+16-y;
dy=-dy;
boom();
}
//配置hgeQuad結構中的頂點
quad.v[0].x=x-16;
quad.v[0].y=y-16;
quad.v[1].x=x+16;
quad.v[1].y=y-16;
quad.v[2].x=x+16;
quad.v[2].y=y+16;
quad.v[3].x=x-16;
quad.v[3].y=y+16;
return false ;
}
Q:什么是幀回調函數?有什么用處?
A:這個幀回調函數是用來表示游戲邏輯的地方,會在后面的代碼中設置這個函數被調用的頻率,一般以每秒多少次表示。在這個函數中,我們就可以進行游戲邏輯的編寫,注意此函數在返回true的情況下,游戲的邏輯將結束,而在返回false的情況下只是代表此次的函數調用結束了,並不是游戲的邏輯結束了(以后不會再被調用,稱為邏輯結束)。
Q:這里的計算問題是什么進行計算的?
A:通過分析代碼發現了這里的計算是以圓球圖案的中心來進行計算的,以全局變量x,y表示圓球圖案中心的坐標。然后使用dx,和dy表示在一次幀回調函數調用中,圓球圖案中心移動的距離。當明白了這點之后,剩下的計算部分就比較簡單了。以dx,dy表示圓球中心坐標的改變,正的代表向右或下進行移動,負的代表向左和右進行移動。dt表示離上次調用的時間間隔,根據設置的FPS值,計算出這個值應該是1/100=0.01秒,調試發現dt值確實等於這個。而在我們按下了一個或者多個按鍵的時候,就可以通過speed*dt來修正dx,dy的值。注意這里的一個比較巧妙的設計,作者在定義全句變量的時候定義了一個名為friction(摩擦力)的全局變量,由於這個變量小於1,所以使用dx*=friction,dy*=friction,來進行計算的話,在dx,dy保持不變的情況下就會慢慢的變小,直至變為0,這就導致了游戲中圓球團在后來慢慢的變成的靜止不動的效果。至於碰撞的處理就根據游戲界面的大小簡單的使用返回距離來表示碰撞。
//定義重繪函數,每次繪圖時,調用此函數
bool ReDraw()
{
hge->Gfx_BeginScene(); //開始繪圖
hge->Gfx_Clear(0); //清空背景
hge->Gfx_RenderQuad(&quad); //重繪圖片
hge->Gfx_EndScene(); //結束繪圖
return false ;
}
Q:重繪函數的作用是什么?
A:重繪函數是在窗口需要重繪的時候進行調用的。和幀回調函數差不多,也是一種回調函數。在這個函數里面通過調用Gfx_BeginScene來開始繪制,使用Gfx_RenderQuad()函數來繪制一個hgeQuad結構中的物體。Gfx_Clear(0)函數可以清空游戲的背景,然后進行重繪。Gfx_EndScene函數會結束繪制,並且更新窗口。
Q:Gfx_Clear是帶參數的函數,它有哪些參數?分別表示什么?
A:Gfx_Clear函數中帶一個DWORD的參數,其中表示的是用指定的ARGB顏色來清除窗口,如果參數為0就表示用黑色來清除窗口。
//定義WinMain函數
int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int)
{
hge = hgeCreate(HGE_VERSION); //創建HGE
//設置狀態屬性
hge->System_SetState(HGE_FRAMEFUNC,FrameFunc); //設置幀回調函數
hge->System_SetState(HGE_WINDOWED,true); //設置是否全屏
hge->System_SetState(HGE_USESOUND,true); //是否使用音樂
Tip:注意這里,如果我們要加載音效的話,這里就需要設置為true
hge->System_SetState(HGE_TITLE,"My First HGE Window -by XJ"); //設置標題欄
hge->System_SetState(HGE_LOGFILE,"log.txt"); //設置日志文件
hge->System_SetState(HGE_RENDERFUNC,ReDraw); //設置重繪函數
hge->System_SetState(HGE_FPS,100); //設置每秒FrameFunc調用的次數
hge->System_SetState(HGE_SCREENWIDTH,800); //設置屏幕寬度
hge->System_SetState(HGE_SCREENHEIGHT,600); //設置屏幕高度
hge->System_SetState(HGE_SCREENBPP,32); //設置像素位數為32bit/pix
if(hge->System_Initiate()) //初始化hge
{
snd = hge->Effect_Load("menu.wav"); //加載音效
quad.tex =hge->Texture_Load("particles.png"); //加載紋理圖片進行貼圖
Q:為什么要在這里加載?在其他地方可以不?
A:經過試驗表明,如果在沒有調用System_Initiate函數之前調用資源加載的函數,調用會失敗,這里需要在以后注意,只有在初始化之后,我們才能夠調用加載資源的函數。
quad.blend = BLEND_ALPHAADD | BLEND_COLORMUL | BLEND_ZWRITE ; //設置混色模式
Q:混色到底要如何使用?混色的參數要如何設置才能達到自己想要的效果?
A:???
if(!snd || !quad.tex)
{
// If one of the data files is not found, display
// an error message and shutdown.
MessageBox(NULL, "Can't load MENU.WAV or PARTICLES.PNG", "Error", MB_OK | MB_ICONERROR | MB_APPLMODAL);
hge->System_Shutdown();
hge->Release();
return 0;
}
for(int i = 0 ; i < 4 ; i ++)
{
quad.v[i].z = 0.5f ; //設置Z序
quad.v[i].col = 0xFFFFA000 ; //設置頂點顏色
}
Q:什么是頂點的Z序?
A:Z序就是從屏幕里到外的一個軸,一般用來顯示立體的效果時需要使用它。而在上面由於同一的都是0.5所以沒有看出什么效果,如果修改下,將這四個頂點的Z序改變成不一的,看看情況如何?通過實驗發現,不管將Z序的值設置為多少,對於游戲的顯示來說,沒有任何改變。查詢官網上的資料,說了如果Z-BUFFER沒有啟動的話,Z-order的值會被忽略掉,這里可能就是因為沒有啟用Z-BUFFER。
Q:如何使用ARGB顏色?前面的A值表示什么?
A:前面的A值表示的是顏色的透明度是多少。這個透明度是用來在混合的時候發生作用的,如果不進行混合,那么指定任何值都沒有關系。但是一旦進行混合,我們就需要注意這個A值所代表的意思。白色(FF)表示的是當前這個顏色沒有透明度,而黑色(00)表示的是當前這個衍射全透明,而介於兩者之間的就是在混合的時候,將這種顏色設置為半透明狀態。而在進行混合時A值起到什么作用一般根據混合的模式不同,A的作用也會不同。
//設置紋理的位置
quad.v[0].tx=96.0/128.0 ; quad.v[0].ty=64.0/128.0 ;
quad.v[1].tx=128.0/128.0; quad.v[1].ty=64.0/128.0 ;
quad.v[2].tx=128.0/128.0; quad.v[2].ty=96.0/128.0 ;
quad.v[3].tx=96.0/128.0 ; quad.v[3].ty=96.0/128.0 ;
Q:紋理的坐標是什么意思?為什么要這么計算?
A:在hgeVertex結構中含有兩個float參數,表示的是紋理的坐標,范圍在0.0-1.0之間。要想了解如何定位這個紋理坐標我們來看下資源文件中的particles.png圖片。
從圖片中我們可以看出在資源文件中存在着很多的圖案,為什么此實例中沒有看到其他的圖案了?答案就在於頂點結構中的兩個紋理坐標。
我們知道hgeQuad中加載了一個紋理,同時保存了4點的hgeVertex結構。接下來我們看看hgeVertex結構
struct hgeVertex
{
float x , y ; //頂點坐標
float z ; //Z序坐標
DWORD col ; //頂點顏色
float tx , ty ; //頂點在紋理上的坐標
};
注意看最后兩個參數,tx,ty。它們表示的是所定義的頂點在紋理中的坐標。即這個頂點與紋理圖片中的哪個點相對應,而第一,二個參數的意思是這個頂點在顯示區域的位置坐標。比如上面代碼中設置的紋理坐標,從圖片中分析可以知道v[0]與紋理中的(96,64)綁定在一起,v[1]與紋理中的(128,64)綁定在一起,v[2]與紋理中的(128,96)綁定在一起,v[3]與紋理中的(96,96)綁定在一起。由於紋理坐標的范圍是在0.0-1.0之間,所以這些坐標點分別除上了像圖片的寬度或者高度128,來計算比例。這樣四個點就分別對應於紋理中的包含圓球圖案的矩形的四個點,也就是說在調用Gfx_RenderQuad的時候,就會根據頂點結構中的x,y坐標繪制這個4個頂點,然后在貼上這四個頂點所綁定的圖案,這就導致了為什么在程序中引入的是整張圖片,而在游戲中只出現了一個圓球圖案的情況。細心的讀者可能注意到了,在定義紋理坐標時,這四個頂點的順序不是任意的,而是按照順時針旋轉的方向來定義這四個頂點的,這里需要注意。
hge->System_Start(); //開始幀回調函數的執行
Q: 為什么調用System_Start之后就將資源釋放掉?
A: 在官網有這樣一段話,“Now we're ready to start the game loop with the System_Start function. When the frame function returns trueand the game loop is finished we should free the loaded texture and the sound effect:”
這句話的意思是說我們調用System_Start來開始游戲的循環。循環包括圖形圖像的繪制,音效的播放,游戲的邏輯和按鍵的判斷等等。當幀回調函數返回true的是偶,System_Start才會返回。所以System_Start返回了就代表游戲結束了,我們需要將游戲中使用的全部資源都釋放掉。
hge->Texture_Free(quad.tex); //釋放紋理資源
hge->Effect_Free(snd); //釋放音效資源
}
else
{
MessageBox(NULL,hge->System_GetErrorMessage(),"Error",MB_OK | MB_ICONERROR);
}
hge->System_Shutdown();
Tip:注意先要關閉,然后在釋放。
hge->Release();
return 0 ;
}
Q:關於Z序Z-BUFFER的開啟有什么作用?如何使用?
A:這個問題,期待官網上后續的教程可以有效的演示如何進行操作。
以下是程序的完整代碼:
#include<hge.h>
#pragma comment(lib,"hge.lib")
//定義全局變量
HGE * hge = NULL ;
hgeQuad quad ; //用於保存繪圖的頂點,紋理,和混色的函數
HEFFECT snd ; //保存音效的句柄
float x = 100.0f , y = 100.0f ;
float dx = 0.0f , dy = 0.0f ;
const float speed = 90 ;
const float friction = 0.98f ;
//定義播放音效的函數
void boom()
{
int pan = int((x-400)/4);
float pitch = (dx*dx+dy*dy)*0.0005f + 0.2f ;
hge->Effect_PlayEx(snd,100,pan,pitch); //snd是音頻資源的句柄,100表示聲音大小,pan表示左右聲道,pitch表示播放頻率
}
//定義幀回調函數
bool FrameFunc()
{
float dt = hge->Timer_GetDelta(); //獲取自上次調用此函數到此次調用此函數的時間間隔
if(hge->Input_GetKeyState(HGEK_ESCAPE))
return true ;
//根據不同的按鍵,使用速度和延遲時間來修正位置
if(hge->Input_GetKeyState(HGEK_LEFT))
dx-=speed*dt ;
if(hge->Input_GetKeyState(HGEK_RIGHT))
dx+=speed*dt ;
if(hge->Input_GetKeyState(HGEK_UP))
dy-=speed*dt ;
if(hge->Input_GetKeyState(HGEK_DOWN))
dy+=speed*dt ;
//做一些運動的計算
dx*=friction;
dy*=friction;
x+=dx;
y+=dy;
if(x>784)
{
x=784-(x-784);
dx=-dx;
boom();
}
if(x<16)
{
x=16+16-x;
dx=-dx;
boom();
}
if(y>584)
{
y=584-(y-584);
dy=-dy;
boom();
}
if(y<16)
{
y=16+16-y;
dy=-dy;
boom();
}
//配置hgeQuad結構中的頂點
quad.v[0].x=x-16;
quad.v[0].y=y-16;
quad.v[1].x=x+16;
quad.v[1].y=y-16;
quad.v[2].x=x+16;
quad.v[2].y=y+16;
quad.v[3].x=x-16;
quad.v[3].y=y+16;
return false ;
}
//定義重繪函數,每次繪圖時,調用此函數
bool ReDraw()
{
hge->Gfx_BeginScene(); //開始繪圖
hge->Gfx_Clear(0); //清空背景
hge->Gfx_RenderQuad(&quad); //重繪圖片
hge->Gfx_EndScene(); //結束繪圖
return false ;
}
//定義WinMain函數
int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int)
{
hge = hgeCreate(HGE_VERSION); //創建HGE
//設置狀態屬性
hge->System_SetState(HGE_FRAMEFUNC,FrameFunc); //設置幀回調函數
hge->System_SetState(HGE_WINDOWED,true); //設置是否全屏
hge->System_SetState(HGE_USESOUND,true); //是否使用音樂
hge->System_SetState(HGE_TITLE,"My First HGE Window -by XJ"); //設置標題欄
hge->System_SetState(HGE_LOGFILE,"log.txt"); //設置日志文件
hge->System_SetState(HGE_RENDERFUNC,ReDraw); //設置重繪函數
hge->System_SetState(HGE_FPS,100); //設置每秒FrameFunc調用的次數
hge->System_SetState(HGE_SCREENWIDTH,800); //設置屏幕寬度
hge->System_SetState(HGE_SCREENHEIGHT,600); //設置屏幕高度
hge->System_SetState(HGE_SCREENBPP,32); //設置像素位數為32bit/pix
if(hge->System_Initiate()) //初始化hge
{
snd = hge->Effect_Load("menu.wav"); //加載音效
quad.tex =hge->Texture_Load("particles.png"); //加載紋理圖片進行貼圖
quad.blend = BLEND_ALPHAADD | BLEND_COLORMUL | BLEND_ZWRITE ; //設置混色模式
if(!snd || !quad.tex)
{
// If one of the data files is not found, display
// an error message and shutdown.
MessageBox(NULL, "Can't load MENU.WAV or PARTICLES.PNG", "Error", MB_OK | MB_ICONERROR | MB_APPLMODAL);
hge->System_Shutdown();
hge->Release();
return 0;
}
for(int i = 0 ; i < 4 ; i ++)
{
quad.v[i].z = 0.5f ; //設置Z序
quad.v[i].col = 0xFFFFA000 ; //設置頂點顏色
}
//設置紋理坐標的位置
quad.v[0].tx=96.0/128.0 ; quad.v[0].ty=64.0/128.0 ;
quad.v[1].tx=128.0/128.0; quad.v[1].ty=64.0/128.0 ;
quad.v[2].tx=128.0/128.0; quad.v[2].ty=96.0/128.0 ;
quad.v[3].tx=96.0/128.0 ; quad.v[3].ty=96.0/128.0 ;
hge->System_Start(); //開始幀回調函數的執行
hge->Texture_Free(quad.tex); //釋放紋理資源
hge->Effect_Free(snd); //釋放音效資源
}
else
{
MessageBox(NULL,hge->System_GetErrorMessage(),"Error",MB_OK | MB_ICONERROR);
}
hge->System_Shutdown();
hge->Release();
return 0 ;
}