提要:本文重點讨論開源遊戲開發庫Allegro(Allegro低級遊戲例程),同時涉及到一些深度技術并提供了一個簡單的示例程式,幫你進一步确定它是否是适合你的開發平台。
<b>一、 一個适于多環境的引擎</b>
Allegro最開始被研發于八十年代後期古老的
Atari
ST平台上,随後被快速地移植到流行的DJGPP環境(一個在九十年代早期流行的32位的MS-DOS擴充程式)。此後,Allegro被移植到最為流行
的Windows C++開發環境中,包括VS,MinGW,Cygwin和Borland
C++。另外的支援它的平台包括Linux,BeOS,QNX,Mac OSX以及幾乎任何其它帶有X11庫的Unix平台上。
Allegro能着色到各種類型的位圖和硬體加
速的環境中,例如DirectX,XWindows,SVGAlib,FreeBE/AF,CGDirectDisplay,QuickDraw,等等。
Allegro并不想提供它自己的3D環境或模拟器,但是OpenGL可以被容易地內建,這是通過使用AllegroGL庫-它提供了一個類似于GLUT
的接口(包括擴充管理)-實作的。
<b>二、 性能概要</b>
在進一步使用API開發前,讓我們看一下Allegro提供的總體功能:
·具體到像素級的繪圖函數,包括平坦陰影,gouraud陰影,紋理貼圖,z緩沖的多邊形和圓繪制,填充,貝塞爾樣條曲線,圖案填充,精靈,blitting(位圖複制),位圖計算縮放和旋轉,半透明/光效果以及比例字型支援的文本輸出
·FLI/FLC(在計算機生成的動畫方面,這種格式比MPEG有更高的壓縮性能)動畫播放器
·播放背景MIDI音樂,可達64種同時的聲音效果,并能錄制樣本波形和MIDI輸入(聲音平台支援,包括WaveOut,DirectSound,OSS,ESD,CoreAudio和QuickTime,等等)
·容易地存取滑鼠,鍵盤,遊戲杆等裝置,還支援高分辨率定時器中斷,包括一個DOS版本的垂直折回中斷模拟器
·讀/寫LZSS壓縮檔案的例程
·數學函數,包括定點算術,表查找和3D矢量/矩陣/四元數操作
·GUI對話框管理器和檔案選擇器
·内建地支援16位和UTF-8格式的Unicode字元
<b>三、 使用引擎</b>
使用Allegro進行開發,就象在許多其它遊戲場合下一樣,遊戲的總體結構都包括遊戲開始前的初始化,遊戲循環以及遊戲完成後的清理。初始化意味着既
包含Allegro啟動代碼也包含在開始的位置實作基本地裝載或生成你的遊戲級别。在建立你的初始化代碼時,啟動Allegro基本上沒有什麼代價付出
(見圖1).
如果你需要很多螢幕相關的真實性能,建議你首先禮貌地用get_gfx_mode_list()函數查詢一下最大可用方式:
#include <allegro.h> //必須放于系統頭檔案的引用之後
set_color_depth(32); // 預設情況下使用8位顔色
if (set_gfx_mode(GFX_AUTODETECT, 640, 480, 0, 0) != 0) {
abort_on_error("Couldn’t set a 32 bit color resolution");
}
set_gfx_mode()的最後兩個參數用于指定虛拟緩沖區的大小-我們的圖形螢幕存儲于其中。這可以使建立一個卷邊遊戲-其中地形是連續移動的-變得容易。例如,你可能要使虛拟緩沖區,比方說,寬出20%以留出足夠的空間來平滑卷動新的精靈和地形。
<b>四、 一個完整的Allegro執行個體</b>
本教程将使用Kee-Yip Chan的SnookerClone示範程式,它是基于James Lohr的另一個具有相同名字的示範程式。圖1顯示了示範程式的基本螢幕快照。
圖1.Kee-Yip Chan的"SnookerClone"示範程式
這個工程向你展示了許多不同的Allegro技術,包括動畫,鍵盤輸入和滑鼠輸入,碰撞和遊戲實體知識(例如重力)。它利用了三個主要的元素:一個有8
個扶手的旋轉的車輪,一個用箭頭鍵來控制的大紅球,還有一些從頂部往下墜落的藍球。車輪以接觸方式推動紅球,而當紅球碰上藍球時,它們之間互相影響。
下列是完整的Allegro示範程式的代碼:
1 #include <allegro.h>
2 vector<Point> g_points; //aka球上點的清單
3 vector<Joint> g_joints; //實體對象清單,如車輪和緩沖器
4 kVec g_accControl;
6 int main(void)
7 {
8 allegro_init(); // 初始化allegro.
9 install_keyboard(); // 啟動鍵盤.
10 install_mouse(); // 啟動滑鼠.
11 install_timer(); //過程show_mouse()所需要;
13 // 建立一個800x600的非全屏視窗.
14 set_gfx_mode(GFX_AUTODETECT_WINDOWED, 800, 600, 0, 0);
16 set_window_title("Kee-Yip Chan’s Snooker Clone");
17 text_mode(-1); // 文本将被畫在透明的背景之上
19 BITMAP* buffer = create_bitmap(SCREEN_W, SCREEN_H);
//建立一張位圖用于雙緩沖.
21 // 初始化資料.
22 create_joints(g_joints); //注冊車輪、地闆和緩沖器的寫死的螢幕位置
25 // 建立頂點以組成aka球: 玩家所用球和三個藍球
26 // 的位置, 速度, 大小和品質.
27 g_points.push_back(Point(kVec(100, 300),kVec(0, 0),16, 10));
// 玩家.
28 g_points.push_back(Point(kVec(50, 40), kVec(0, 0),12, 5));
// 中等的球.
29 g_points.push_back(Point(kVec(80, 40), kVec(0, 0) 12, 5));
//中等的球.
30 g_points.push_back(Point(kVec(110, 40),kVec(0, 0),6, 1));
// 小球.
32 //主循環,在按ESC鍵後退出
33 while(!key[KEY_ESC]) { //檢查輸入.
34 if(key[KEY_UP])
35 g_accControl.y = -0.07; //Jet pack.向上加速
36 if(key[KEY_LEFT])
37 g_accControl.x = -0.07; //左走.向左加速
38 if(key[KEY_RIGHT])
39 g_accControl.x = 0.07; //右走.向右加速
41 static bool leftMousePressed = false,
rightMousePressed = false;
42 if(mouse_b & 1) { //滑鼠左鍵按下
43 if(!leftMousePressed){
44 leftMousePressed = true; // 建立一個新球.
45 g_points.push_back(Point(kVec(mouse_x, mouse_y),kVec(0, 0), 12, 5));
46 }
47 }
48 if(!(mouse_b & 1))
49 //保證不重複滑鼠按鍵
50 //否則,就會出現許多的新球
51 leftMousePressed = false;
52 if(mouse_b & 2) { //滑鼠右鍵按下
53 if(!rightMousePressed){
54 rightMousePressed = true; // 建立一個新球
55 g_points.push_back(Point(kVec(mouse_x, mouse_y),kVec(0, 0), 6, 1));
56 }
57 }
58 if(!(mouse_b & 2))
59 //保證不重複滑鼠按鍵
60 //否則,就會出現許多的新球.
61 rightMousePressed = false;
63 doPhysics();
65 // 着色:如果我們能再次使用緩沖區,則清除它;
//否則,舊圖像将滞留顯示
66 //用白色進行清除.
67 clear_to_color(buffer, makecol(255, 255, 255));
68 for(unsigned i = 0; i < g_points.size(); i++) {
//畫點.
69 //畫一個實心球
70 circlefill(buffer, //畫向緩沖區
71 g_points[i].position.x,g_points[i].position.y,// aka 球的中心點的位置
72 g_points[i].size, // 半徑.
73 (i == 0) ? makecol(255, 0, 0) : makecol(0, 0, 255)); //紅色如果是玩家;否則為藍色
75 // 畫一個輪廓球.
76 circle(buffer, //畫向緩沖區
77 g_points[i].position.x,g_points[i].position.y, // aka 球的中心點的位置.
78 g_points[i].size, // 半徑.
79 makecol(0, 0, 0)); //紅色如果是玩家;否則為藍色.
81 }
83 // 畫接合點
84 for (unsigned i = 0; i < g_joints.size(); i++)
85 line(buffer, //畫向緩沖區
86 g_joints[i].p1.x, g_joints[i].p1.y, // 點 1.
87 g_joints[i].p2.x, g_joints[i].p2.y, // 點 2.
88 makecol(0, 0, 0)); // 黑顔色.
89 );
91 // 列印指令.
92 textout(buffer, font, "Left Mouse Button - new big ball Right Mouse Button - new small ball",
93 125, 1, makecol(0, 0, 0));
95 textout(buffer, font, "Arrow Keys - move red ball",
96 300, 592, makecol(0, 0, 0));
98 show_mouse(buffer); // 畫滑鼠光标.
100 draw_sprite(screen, buffer, 0, 0);// 把緩沖區中的資料畫向螢幕.
101 } // while循環結束
103 return 0;
105 }END_OF_MAIN();
33-101行包括了典型的遊戲程式設計循環模式。遊戲繼續進行直到玩家按下ESC鍵退出為止。34-39行支援同時進行的鍵盤輸入,因為你可以按下向上和向左箭頭鍵來擷取粗略的斜向運動。
在41-61行,滑鼠動作被捕獲到全局變量mouse_b(用于按鈕),mouse_x和mouse_y。如果你一直在使用一滾輪滑鼠,你還可以使用變量mouse_z。我們對反向彈跳邏輯進行了一點寫死以確定每次滑鼠按下事件隻有一個球下落。
第63行調用doPhysics(),其目的是旋轉車輪的線段,更新球位置,檢測球碰撞和适當地改變它們的方向矢量。這個子產品(350行的數學代碼)有點深入了些,但它确實是一個一流的實作,值得你深入研究。
餘下的代碼,65-101行,開始着色,在典型的示例程式中這屬于正常實作部分。這裡的着色用典型的雙緩沖區技術,下一次螢幕變化被計算出來并進行脫屏
繪制并在最的一毫秒進行緩沖交換(第100行)。這確定了視覺的連續性又減少了煩人的閃爍-對象看上去是随機地繪制的。在着色代碼部分,對line()和
circlefill()的調用是相當直接的:circlefill()以x,y,半徑和填充顔色作為參數。
textout_ex
()函數的功能稍強于textout()(示于92-96行),允許你指定前景和背景顔色。Allegro提供例程以直接從GRX格式.fnt檔案,
8x8或8x16
BIOS格式.fnt檔案,位圖圖象以及資料檔案格式中裝入字型。作為選擇,你能導入一種大範圍的Unicode字型,這可以通過寫一個.txt腳本-它
為每一範圍的字元指定相應的不同的源檔案-來實作。如果你想要支援TrueType,那麼你需要AllegroTTF或相同功能的插件。
最後,在第100行的draw_sprite()實作一個覆寫性複制新生成的位圖到第14行建立的螢幕對象上。覆寫性複制意指隻有非透明的顔色像素被複制。在本例中,我确信它已被退化成一個"blit"(塊複制)轉儲。
<b>五、 Allegro的音頻</b>
這個snooker示範程式隻涉及到了一些最基本的圖形和I/O函數,但是并沒有用到Allegro的音頻開發包。該包中的MIDI混頻,音響效果和錄
音API,其效果達到或超過幾乎每一個我所見過的專業的聲音庫。Allegro音頻應用軟體大量存在,包括WinCab-一個MP3和OGG
Vorbis音樂唱片機,還有LouTronic Rhythm Box-一個鼓聲生成合成器,它具有可全面融合到一起的snare鼓,低音鼓和hi
hat的效果。下面我們簡單地回顧Allegro音頻API的一小部分。
每一個使用音頻的程式都應該調用reserve_voices()來指定數字和MIDI聲音驅動程式分别使用的聲音的數目。接下去,你能控制這些音頻軌道的混合.
你可以非常容易地象下面這樣插入一個音軌:
MIDI *midFile = load_midi("myfile.mid’);
play_midi(midFile, TRUE);//連續循環
對于更複雜的需要,你可以安裝三個鈎子函數之一,它們可以使你攔截MIDI玩家事件。如果被設定為非NULL,這些例程将在每次MIDI消息,元事件和系統獨占的資料塊中被分别調用。
Allegro的數字音頻系統被設計為從最基本的配置到可高度擴充的。你能容易安裝讀取器和寫入器來處理新的或者不同的音頻檔案類型, 例如:
register_sample_file_type("mp3",load_mp3,NULL);//安裝MP3讀取器
當正播放數字音頻時,你可以随時編輯它。下列代碼改變将在播放一個樣本參數時改變該樣本(用于操作循環播放的聲音):
void adjust_sample(const SAMPLE *spl, int vol, int pan, int freq, int loop);
你能改變音量,平移音頻資料并清除循環标志,在下次執行到循環末尾時,這将停止該樣本。如果在播放相同樣本的好幾個副本,這會調整它遇到的第一個副本。如果該樣本沒有播放,對它沒有任何影響。