• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

              C++博客 :: 首頁 :: 聯(lián)系 ::  :: 管理
              163 Posts :: 4 Stories :: 350 Comments :: 0 Trackbacks

            常用鏈接

            留言簿(48)

            我參與的團(tuán)隊(duì)

            搜索

            •  

            積分與排名

            • 積分 - 400062
            • 排名 - 59

            最新評論

            閱讀排行榜

            評論排行榜

            歡迎來到32課. 這課大概是在我所寫作已來最大的一課. 超過1000 行代碼和約1540行的HTML. 這也是第一課用到我新的NeHeGL 基本代碼. 這課寫了很長時間, 但我想他是值得期待的. 一些知識點(diǎn)用到是: Alpha 混合, Alpha 測試, 讀取鼠標(biāo), 同時用到Ortho 和透視, 顯示客戶鼠標(biāo), 按深度排列物體, 動畫幀從單張材質(zhì)圖 和更多要點(diǎn), 你將學(xué)到更多精選的內(nèi)容!
            最初的版本是在屏幕上顯示三個物體,當(dāng)你單擊他們將改變顏色. 很有趣!?! 不怎樣! 象往常一樣, 我想給你們這些家伙留下一個超極好的課程. 我想使課程有趣, 豐富,當(dāng)然..美觀. 所以, 經(jīng)過幾個星期的編碼之后, 這課程完成了! 即使你不編碼,你仍會喜歡這課. 這是個完整的游戲. 游戲的目標(biāo)是射擊更多的靶子, 在你失去一定數(shù)的靶子后,你將不能再用鼠標(biāo)單擊物體.

            我確信會有批評,但我非常樂觀對這課! 我已在從深度里選擇和排序物體這個主題里找到快樂!

            一些需要注意的代碼. 我僅僅會在lesson32.cpp里討論. 有一些不成熟的改動在 NeHeGL 代碼里. 最重要的改動是我加入鼠標(biāo)支持在 WindowProc(). 我也加入 int mouse_x, mouse_y 在存鼠標(biāo)運(yùn)動. 在 NeHeGL.h 以下兩條代碼被加入: extern int mouse_x; & extern int mouse_y;

            課程用到的材質(zhì)是用 Adobe Photoshop 做的. 每個 .TGA 文件是32位圖片有一個alpha 通道. 若你不確信自已能在一個圖片加入alpha通道, 找一本好書,上網(wǎng),或讀 Adobe Photoshop幫助. 全部的過程非常相似,我做了透明圖在透明圖課程. 調(diào)入你物體在 Adobe Photoshop (或一些其它圖形處理程序,且支持alpha 通道). 用選擇顏色工具選你圖片的背景. 復(fù)制選區(qū). 新建一個圖. 粘貼生成新文件. 取消圖片選擇,你圖的背景應(yīng)是黑色. 使周圍是白色. 選全部圖復(fù)制. 回到最初的圖且建一個alpha 通道. 粘貼黑和白透明圖你就完成建立alpha通道.存圖片為32位t .TGA文件. 使確定保存透明背景是選中的,保存!

            如以往我希望你喜歡這課程. 我感興趣你對他的想法. 若你有些問題或你發(fā)現(xiàn)一些問題,告訴我. 我匆忙的完成這課程 所以若你發(fā)現(xiàn)哪部分很難懂,給我發(fā)些郵件,然后我會用不同的方式或更詳細(xì)的解釋!

             
              

            #include <windows.h>                               
            #include <stdio.h>                               
            #include <stdarg.h>                               
            #include <time.h>                               
            #include "NeHeGL.h"                           
              
             在第1課里, 我提倡關(guān)于適當(dāng)?shù)姆椒ㄟB接到 OpenGL 庫. 在 Visual C++ 里點(diǎn)擊’項(xiàng)目’,設(shè)置,連接項(xiàng). 移下到 對象/庫 模塊 加入 OpenGL32.lib, GLu32.lib 和 GLaux.lib. 預(yù)編譯一個需要的庫的失敗將使編譯器找出所出的錯誤. 有時你不想發(fā)生! 使事情更壞, 若你僅僅預(yù)編譯庫在debug 模式, 和有人試在release 模式建立你程序... 更多的錯誤. 有許多人看代碼. 他們大多數(shù)是新程序員. 他們?nèi)〉侥愕拇a, 試著編譯. 他們得到錯誤, 刪掉代碼,移走.
            下而的代碼告訴編譯者去連接需要的庫. 一點(diǎn)多些的字, 但少些以后的頭痛. 在這個課程, 我們將連接 OpenGL32 庫,GLu32庫 和 WinMM庫 (用來放音樂). 在這課程我們會調(diào)入 .TGA 文件,所以我們不用 GLaux庫.

             
              

            #pragma comment( lib, "opengl32.lib" )                        // 在鏈接時連接Opengl32.lib庫
            #pragma comment( lib, "glu32.lib" )                            // 鏈接glu32.lib庫
            #pragma comment( lib, "winmm.lib" )                            // 鏈接winmm.lib庫

              
             下而的3 行檢查若 CDS_FULLSCREEN 已被你的編譯器定義. 若還沒被定義, 我們給 CDS_FULLSCREEN 為 4. 馬上你完全部丟掉... 一些編譯器不給 CDS_FULLSCREEN 變量,將返回一個錯誤,但是 CDS_FULLSCREEN 是有用的! 防止出錯消息, 我們檢查若 CDS_FULLSCREEN 是否定義,若出錯, 我們定義他. 使每人生活更簡單.
            我們再定義 DrawTargets函數(shù), 為窗口和按鍵設(shè)變量. 你若不懂定義,讀一遍MSDN術(shù)語表.保持清醒, 我不是教 C/C++, 買一本好書若你對非gl代碼要幫助!

             
              

            #ifndef        CDS_FULLSCREEN                           
            #define        CDS_FULLSCREEN 4                       
            #endif                                   

            void DrawTargets();                               

            GL_Window*    g_window;
            Keys*        g_keys;

              
             下面的代碼是用戶設(shè)置變量. base 是將用到的字體顯示列表的開始列表值. roll 是將用到的移動的大地和建立旋轉(zhuǎn)的云. level 應(yīng)是級別 (我們開始是 1級). miss 保留失去了多少物體. 他還用來顯示用戶的士氣(不丟失意味著高士氣). kills 保留每級打到多少靶子. score 會保存運(yùn)行時打中的總數(shù), 同時用到結(jié)束比賽!
            最后一行是讓我們通過結(jié)構(gòu)比較的函數(shù). 是等待qsort 最后參數(shù)到 type (const *void, const *void).

             
              

            // 用戶定義的變量
            GLuint        base;                                // 字體顯示列表
            GLfloat        roll;                                // 旋轉(zhuǎn)的云
            GLint        level=1;                                // 現(xiàn)在的等級
            GLint        miss;                                // 丟失的數(shù)
            GLint        kills;                                // 打到的數(shù)
            GLint        score;                                // 當(dāng)前的分?jǐn)?shù)
            bool        game;                                // 游戲是否結(jié)束?

            typedef int (*compfn)(const void*, const void*);                    // 定義用來比較的函數(shù)

              
             現(xiàn)在為我們物體的結(jié)構(gòu). 這個結(jié)構(gòu)存了所有一個物體的信息. 旋轉(zhuǎn)的方向, 若被打中, 在屏幕的位置, 等等.
            一個快速運(yùn)動的變量... rot 我想讓物體旋轉(zhuǎn)特別的方向. hit 若物體沒被打中將是 FALSE . 若物體給打中或飛出, 變量將是 TRUE.

            變量frame 是用來存我們爆炸動畫的周期. 每一幀改變增加一個爆炸材質(zhì). 在這課有更多在不久.

            保存單個物體的移動方向, 我們用變量 dir. 一個dir 能有4 個值: 0 - 物體左移, 1 - 物體右移, 2 - 物體上移 和最后 3 - 物體下移

            texid 能是從0到4的數(shù). 0 表示是藍(lán)面材質(zhì), 1 是水桶材質(zhì), 2 是靶子的材質(zhì) , 3 是 可樂的材質(zhì) 和 4 是 花瓶 材質(zhì). 最近在調(diào)入材質(zhì)的代碼, 你將看到先前5種材質(zhì)來自目標(biāo)圖片.

            x 和 y 兩者都用來記屏模上物體的位置. x 表示物體在 x-軸, y 表示物體在 y-軸.

            物體在z-軸上的旋轉(zhuǎn)是記在變量spin. 在以后的代碼, 我們將加或減spin基數(shù)在旅行的方向上.

            最后, distance 保存我們物體到屏幕的距離. 距離是極端重要的變量, 我們將用他來計(jì)算屏幕的左右兩邊, 而且在對象關(guān)閉之前排序物體,畫出物體的距離.



             
              

            struct objects {
                GLuint    rot;                                // 旋轉(zhuǎn) (0-不轉(zhuǎn), 1-順時針轉(zhuǎn), 2-逆時針轉(zhuǎn))
                bool    hit;                                // 物體碰撞?
                GLuint    frame;                                // 當(dāng)前爆炸效果的動畫幀
                GLuint    dir;                                // 物體的方向 (0-左, 1-右, 2-上, 3-下)
                GLuint    texid;                                // 物體材質(zhì) ID
                GLfloat    x;                                // 物體 X 位置
                GLfloat y;                                // 物體 Y 位置
                GLfloat    spin;                                // 物體旋轉(zhuǎn)
                GLfloat    distance;                                // 物體距離
            };

              
             解釋下面的代碼沒有真正的結(jié)果. 我們在這課調(diào)入TGA圖代替bitmaps圖片. 下面的用來表示TGA圖片數(shù)據(jù)的結(jié)構(gòu)是盡可能好的 . 若你需要詳細(xì)的解釋下面的代碼,請讀關(guān)于調(diào)入TGA 文件的課程.  
              

            typedef struct                                    // 新建一個結(jié)構(gòu)
            {
                GLubyte    *imageData;                            // 圖片數(shù)據(jù) (最大 32 位)
                GLuint    bpp;                                // 圖片顏色深度 每象素
                GLuint    width;                                // 圖片寬度
                GLuint    height;                                // 圖片高度
                GLuint    texID;                                // 貼圖材質(zhì) ID 用來選擇一個材質(zhì)
            } TextureImage;                                    // 結(jié)構(gòu) 名稱

              
             緊接下面的代碼為們10個材質(zhì)和個30物體留出空間. 若你打算在游戲里加更多物體,得增加這個變量到你想到的數(shù) 
              

            TextureImage textures[10];                            // 定義10個材質(zhì)

            objects    object[30];                            // 定義 30 個物體

              
             我不想限制每個物體的大小. 我想瓶子(vase)比can高, 我想水桶bucket比瓶子寬. 去改變一切是簡單的, 我建了一個結(jié)構(gòu)存物體的寬和高.
            我然后在最后一行代碼中設(shè)每個物體的寬高. 得到這個coke cans的寬, 我將檢查size[3].w. 藍(lán)面是 0, 水桶是 1, 和靶子是 2, 等. 寬度表現(xiàn)在 w. 使有意義?



             
              

            struct dimensions {                                // 物體維數(shù)
                GLfloat    w;                                // 物體寬
                GLfloat h;                                // 物體高
            };

            // 每個物體的大小: 藍(lán)面, 水桶, 靶子, 可樂, 瓶子
            dimensions size[5] = { {1.0f,1.0f}, {1.0f,1.0f}, {1.0f,1.0f}, {0.5f,1.0f}, {0.75f,1.5f} };

              
             下面是大段代碼是調(diào)入我們 TGA 圖片和轉(zhuǎn)換他為材質(zhì). 這是同我在第25課所用的一樣的代碼,你可回去看一看.
            我用TGA 圖片的原因是他們是有alpha 通道的. 這個alpha 通道告訴 OpenGL 哪一部分圖是透明的,哪一部分是白底. alpha 通道是被建立在圖片處理程序, 并保存在.TGA圖片里面. OpenGL 調(diào)入圖片, 能用alpha 通道設(shè)置圖片中每個象素透明的數(shù)量.

             
              

            bool LoadTGA(TextureImage *texture, char *filename)                    // 調(diào)入一個TGA 文件到內(nèi)存
            {
                GLubyte        TGAheader[12]={0,0,2,0,0,0,0,0,0,0,0,0};            // (未)壓縮的 TGA 頭
                GLubyte        TGAcompare[12];                        // 用來比較 TGA 頭
                GLubyte        header[6];                        // 首先 6 個有用的字節(jié)
                GLuint        bytesPerPixel;                        // 每象素字節(jié)數(shù)在 TGA 文件使用
                GLuint        imageSize;                        // 用來圖片大小的存儲
                GLuint        temp;                            // 臨時變量
                GLuint        type=GL_RGBA;                        // 設(shè)置默認(rèn)的 GL 模式 為 RBGA

                FILE *file = fopen(filename, "rb");                        // 打開 TGA 文件

                if(    file==NULL ||                            // 文件是否已存在 ?
                    fread(TGAcompare,1,sizeof(TGAcompare),file)!=sizeof(TGAcompare) ||    // 是否讀出12個字節(jié)?
                    memcmp(TGAheader,TGAcompare,sizeof(TGAheader))!=0 ||            // 文件頭是不是我們想要的 ?
                    fread(header,1,sizeof(header),file)!=sizeof(header))            // 若正確則讀下 6 個 Bytes
                {
                    if (file == NULL)                            // 文件是否已存在 ?
                        return FALSE;                        // 返回錯誤
                    else                                // 否則
                    {
                        fclose(file);                        // 若有任何錯誤, 關(guān)掉文件
                        return FALSE;                        // 返回錯誤
                    }
                }

                texture->width  = header[1] * 256 + header[0];                // 定義 TGA 寬
                texture->height = header[3] * 256 + header[2];                // 定義 TGA 高

                 if(    texture->width    <=0 ||                        // 若 寬<=0
                    texture->height    <=0 ||                        // 若 高<=0
                    (header[4]!=24 && header[4]!=32))                    // 若 TGA 是 24 or 32 位?
                {
                    fclose(file);                            // 若有任何錯誤, 關(guān)掉文件
                    return FALSE;                            // 返回錯誤
                }

                texture->bpp    = header[4];                        // 取 TGA 的位每象素 (24 或 32)
                bytesPerPixel    = texture->bpp/8;                        // 除以 8 得到字節(jié)每象素
                imageSize        = texture->width*texture->height*bytesPerPixel;        // 計(jì)算 所需內(nèi)存為 TGA 數(shù)據(jù)

                texture->imageData=(GLubyte *)malloc(imageSize);                // 分配 內(nèi)存 為 TGA 數(shù)據(jù)

                if(    texture->imageData==NULL ||                        // 這個內(nèi)存是否存在?
                    fread(texture->imageData, 1, imageSize, file)!=imageSize)        // 圖片大小與保留內(nèi)存的大小想等 ?
                {
                    if(texture->imageData!=NULL)                    // 圖片數(shù)據(jù)的調(diào)入
                        free(texture->imageData);                    // 若成功, 釋放圖象數(shù)據(jù)

                    fclose(file);                            // 關(guān)掉文件
                    return FALSE;                            // 返回錯誤
                }

                for(GLuint i=0; i<int(imageSize); i+=bytesPerPixel)                // 在圖象數(shù)據(jù)里循環(huán)
                {                                    // 交換第1和第3 Bytes (’紅’red 和 ’藍(lán)’blue)
                    temp=texture->imageData[i];                        // 臨時存儲 圖象的 ’i’
                    texture->imageData[i] = texture->imageData[i + 2];            // 設(shè) 第1 Byte 得到變量 第3 Byte
                    texture->imageData[i + 2] = temp;                    // 設(shè)第3 Byte 得到變量 ’temp’ (第1 Byte 變量)
                }

                fclose (file);                                // 關(guān)掉文件

                // 建立一個貼圖材質(zhì)從以上數(shù)據(jù)
                glGenTextures(1, &texture[0].texID);                        // 生成 OpenGL 材質(zhì) ID

                glBindTexture(GL_TEXTURE_2D, texture[0].texID);                // 綁定我們的材質(zhì)
                glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);        // 線過濾器
                glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);        // 線過濾器

                if (texture[0].bpp==24)                            // 若 TGA 是24 位的
                {
                    type=GL_RGB;                            // 設(shè) ’type’ 為 GL_RGB
                }

                glTexImage2D(GL_TEXTURE_2D, 0, type, texture[0].width, texture[0].height, 0, type, GL_UNSIGNED_BYTE, texture[0].imageData);

                return true;                                // 材質(zhì)建立成功, 返回正確
            }

              
             2D 字體材質(zhì)代碼同我已在前一課用的是一樣的. 然而, 有一些小不同. 第一是你將看到僅僅唯一生成95 顯示列表. 若你看字體材質(zhì), 你會看到只有 95 字母計(jì)算空間在圖片頂,左. 第二個事是你將通知分在16.0f 為 cx 和 我們只分在8.0f 為cy. 我這樣做的結(jié)果是因?yàn)樽煮w材質(zhì)是256 象素寬, 但僅僅一伴就高(128 象素). 所以計(jì)算cx 我們分為16.0f 和計(jì)算分cy 為一半(8.0f).
            若你不懂下面的代碼, 回去讀17課. 建立字體的代碼的詳細(xì)解釋在第17課里!



             
              

            GLvoid BuildFont(GLvoid)                            // 建立我們字體顯示列表
            {
                base=glGenLists(95);                        // 建立 95 顯示列表
                glBindTexture(GL_TEXTURE_2D, textures[9].texID);            // 綁我們字體材質(zhì)
                for (int loop=0; loop<95; loop++)                    // 循環(huán)在 95 列表
                {
                    float cx=float(loop%16)/16.0f;                // X 位置 在當(dāng)前字母
                    float cy=float(loop/16)/8.0f;                // Y 位置 在當(dāng)前字母

                    glNewList(base+loop,GL_COMPILE);                // 開始建立一個列表
                        glBegin(GL_QUADS);                    // 用四邊形組成每個字母
                            glTexCoord2f(cx,         1.0f-cy-0.120f); glVertex2i(0,0);    // 質(zhì)地 / 點(diǎn) 座標(biāo) (底 左)
                            glTexCoord2f(cx+0.0625f, 1.0f-cy-0.120f); glVertex2i(16,0);    // 質(zhì)地 / 點(diǎn) 座標(biāo) (底 右)
                            glTexCoord2f(cx+0.0625f, 1.0f-cy);      glVertex2i(16,16);    // 質(zhì)地 / 點(diǎn) 座標(biāo) (頂 右)
                            glTexCoord2f(cx,         1.0f-cy);      glVertex2i(0,16);    // 質(zhì)地 / 點(diǎn) 座標(biāo) (頂 左)
                        glEnd();                        // 完成建立我們的 四邊形 (字母)
                        glTranslated(10,0,0);                // 移到字體的右邊
                    glEndList();                        // 完成建軍立這個顯示列表
                }                                // 循環(huán)直到所有 256 完成建立
            }

              
             輸出的代碼也在第17課, 但已修改為在屏幕輸出我們的分?jǐn)?shù), 等級和士氣(不斷改變的值).  
              

            GLvoid glPrint(GLint x, GLint y, const char *string, ...)                // 輸出在屏慕的位置
            {
                char        text[256];                        // 保存在我們的字符串
                va_list        ap;                            // 到列表的指針

                if (string == NULL)                            // 若文字為空
                    return;                                // 返回

                va_start(ap, string);                            // 解析字符串
                    vsprintf(text, string, ap);                        // 轉(zhuǎn)換字符串
                va_end(ap);                                // 結(jié)果的字符串

                glBindTexture(GL_TEXTURE_2D, textures[9].texID);                // 選擇我們字體材質(zhì)
                glPushMatrix();                                // 存觀看模式矩陣
                glLoadIdentity();                                // 設(shè)觀看模式矩陣
                glTranslated(x,y,0);                            // 文字輸出位置 (0,0 - 底 左-Bottom Left)
                glListBase(base-32);                            // 選擇字體設(shè)置
                glCallLists(strlen(text), GL_UNSIGNED_BYTE, text);                // 輸出顯示列表中的文字
                glPopMatrix();                                // 取出以前的模式矩陣
            }

              
             這些代碼調(diào)用排序程序. 它比較距離在兩個結(jié)構(gòu)并返回-1 若第一個結(jié)構(gòu)的距離小于第二個 , 1 i若 第一個結(jié)構(gòu)的距離大于第二個 0 否則 (若 距離相等)  
              

            int Compare(struct objects *elem1, struct objects *elem2)            // 比較 函數(shù)
            {
               if ( elem1->distance < elem2->distance)                    // 若 第一個結(jié)構(gòu)的距離小于第二個
                  return -1;                                // 返回 -1
               else if (elem1->distance > elem2->distance)                // 若 第一個結(jié)構(gòu)的距離大于第二個
                  return 1;                                // 返回1
               else                                    // 否則 (若 距離相等)
                  return 0;                                // 返回 0
            }

              
             InitObject() 代碼是來建立每個物體. 我們開始設(shè) rot 為 1. 這使物體順時針旋轉(zhuǎn). 然后設(shè)爆炸效果動畫幀為0(我們不想爆炸效果從中間開始).我們下面設(shè) hit 為 FALSE, 意思是物體還沒被擊中或正開如. 選一個物體材質(zhì), texid 用來給一個隨機(jī)的變量從 0 到 4. 0是blueface 材質(zhì) 和4 是 vase 材質(zhì). 這給我們5種隨機(jī)物體.
            距離變量是在-0.0f to -40.0f (4000/100 is 40)的隨機(jī)數(shù) . 當(dāng)我們真實(shí)的畫物體,我們透過在屏幕上的另10 個單位. 所以當(dāng)物體在畫時, 他們將畫從-10.0f to -50.0f 單位 在屏幕(不挨著, 也不離得太遠(yuǎn)). 我分隨機(jī)數(shù)為 100.0f 得到更精確的浮點(diǎn)數(shù)值.

            在給完隨機(jī)的距離之后, 我們給物體一個隨機(jī)的 y . 我們不想物體低于 -1.5f, 否則他將低于大地, 且我們不想物體高于3.0f. 所以留在我們的區(qū)間的隨機(jī)數(shù)不能高于4.5f (-1.5f+4.5f=3.0f).

            去計(jì)算 x 位置, 用一些狡猾的數(shù)學(xué). 用我們的距離減去15.0f . 除以2 減5*level. 再 減隨機(jī)數(shù)(0.0f 到5) 乘level. 減 5*level rndom(0.0f to 5*level) 這是最高級.

            選一個方向.

            使事情簡單明白x, 寫一個快的例子. 距離是 -30.0f ,當(dāng)前級是 1:

            object[num].x=((-30.0f-15.0f)/2.0f)-(5*1)-float(rand()%(5*1));
            object[num].x=(-45.0f/2.0f)-5-float(rand()%5);
            object[num].x=(-22.5f)-5-{lets say 3.0f};
            object[num].x=(-22.5f)-5-{3.0f};
            object[num].x=-27.5f-{3.0f};
            object[num].x=-30.5f;

            開始在屏模上移 10 個單位 , 距離是 -30.0f. 其實(shí)是 -40.0f.用透視的代碼在 NeHeGL.cpp 文件.


             
              

            GLvoid InitObject(int num)                            // 初始化一個物體
            {
                object[num].rot=1;                            // 順時針旋轉(zhuǎn)
                object[num].frame=0;                        // 設(shè)爆炸效果動畫幀為0
                object[num].hit=FALSE;                        // 設(shè)點(diǎn)擊檢測為0
                object[num].texid=rand()%5;                        // 設(shè)一個材質(zhì)
                object[num].distance=-(float(rand()%4001)/100.0f);            // 隨機(jī)距離
                object[num].y=-1.5f+(float(rand()%451)/100.0f);            // 隨機(jī) Y 位置
                // 隨機(jī)開始 X 位置 基于物體的距離 和隨機(jī)的延時量 (確定變量)
                object[num].x=((object[num].distance-15.0f)/2.0f)-(5*level)-float(rand()%(5*level));
                object[num].dir=(rand()%2);                        // 選一個隨機(jī)的方向

              
             檢查方向
             
              

                if (object[num].dir==0)                            // 若隨機(jī)的方向正確
                {
                    object[num].rot=2;                            // 逆時針旋轉(zhuǎn)
                    object[num].x=-object[num].x;                    // 開始在左邊 (否定 變量)
                }

              
             現(xiàn)在我們檢查texid 來找出所選的的物體. 若 texid 為0, 所選的物體是 Blueface . blueface 總是在大地上面旋轉(zhuǎn). 確定開始時在地上的層, 我們設(shè) y 是 -2.0f.
             
              

                if (object[num].texid==0)                            // 藍(lán)色天空表面
                    object[num].y=-2.0f;                        // 總是在大地上面旋轉(zhuǎn)

              
             下面檢查若texid 是 1. 這樣, 電腦所選物體的是 Bucket. bucket不從左到右運(yùn)動, 它從天上掉下來. 首先我們不得不設(shè) dir 是 3. 這告訴電腦我們的水桶bucket 是掉下來或向下運(yùn)動.
            我們最初的代碼假定物體從左到右運(yùn)動. 因?yàn)閎ucket 是向下落的, 我們得不給它一個新的隨機(jī)的變量 x . 若不是這樣, bucket 會被看不到. 它將不在左邊落下就在屏幕外面. 我們給它一個新的隨機(jī)距離變量在屏幕上. 代替減去15, 我們僅僅減去 10. 這給我們一些幅度, 保持物體在屏幕??. 設(shè)我們的distance 是-30.0f, 從0.0f -40.0f的隨機(jī)變量. 為什么從 0.0f 到 40.0f? 不是從0.0f to -40.0f? 答案很簡單. rand() 函數(shù)總返回正數(shù). 所以總是正數(shù). 另外,回到我們的故事. 我們有個正數(shù) 從0.0f 到 40.0f.我們加距離 最小 10.0f 除以 2. 舉個例子,設(shè)x變量為 15 ,距離是 -30.0f:

            object[num].x=float(rand()%int(-30.0f-10.0f))+((-30.0f-10.0f)/2.0f);

            object[num].x=float(rand()%int(-40.0f)+(-40.0f)/2.0f);

            object[num].x=float(15 {assuming 15 was returned))+(-20.0f);

            object[num].x=15.0f-20.0f;

            object[num].x=-5.0f;

            下面設(shè)y. 我們想水桶從天上下來. 我人不想穿過云. 所以我們設(shè) y 為 4.5f. 剛在去的下面一點(diǎn).

             
              

                if (object[num].texid==1)                        // 水桶(Bucket)
                {
                    object[num].dir=3;                        // 下落
                    object[num].x=float(rand()%int(object[num].distance-10.0f))+((object[num].distance-10.0f)/2.0f);
                    object[num].y=4.5f;                    // 隨機(jī) X, 開始在屏模上方
                }

              
             我們想靶子從地面突出到天上. 我們檢查物體為 (texid 是 2). 若是, 設(shè)方向(dir) 是 2 (上). 用精確的數(shù) x 位置.
            我們不想target 開始在地上. 設(shè) y 初值為-3.0f (在地下). 然后減一個值從0.0f 到 5 乘當(dāng)前 level. 靶子不是立即出現(xiàn). 在高級別是有延時, 通過delay, 靶子將出現(xiàn)在一個在另一個以后, 給你很少時間打到他們.

             
              

                if (object[num].texid==2)                        // 靶子
                {
                    object[num].dir=2;                        // 開始向上飛
                    object[num].x=float(rand()%int(object[num].distance-10.0f))+((object[num].distance-10.0f)/2.0f);
                    object[num].y=-3.0f-float(rand()%(5*level));            // 隨機(jī) X, 開始在下面的大地 + 隨機(jī)變量
                }

              
             所有其它的物體從右到左旅行, 因而不必給任何變量付值來改變物體. 它們應(yīng)該剛好工作在所給的隨機(jī)變量.
            現(xiàn)在來點(diǎn)有趣的材料! "為了alpha 混合技術(shù)正常的工作, 透明的原物必須不斷地排定在從后向前畫". 當(dāng)畫alpha 混合物體是, 在遠(yuǎn)處的物體是先畫的,這是非常重要的, 下面畫緊臨的上面的物體.

            理由是簡單的... Z 緩沖區(qū)防止 OpenGL 從已畫好的混合東西再畫象素. 這就是為什么會發(fā)生物體畫在透明混合之后而不再顯示出來. 為什么你最后看到的是一個四邊形與物體重疊... 很不好看!

            我們已知道每個物體的深度. 因而在初始化一個物體之后, 我們能通過把物體排序,而用qsort 函數(shù)(快速排序sort),來解決這個問題 . 通過物體排序, 我們能確信第一個畫的是最遠(yuǎn)的物體. 這意味著當(dāng)我們畫物體時, 起始于第一個物體, 物體通過用距離將被先畫. 緊挨著那個物體(晚一會兒畫) 將看到先前的物體在他們的后面, 再將適度的混合!

            這文中的這行線注釋是我在 MSDN 里發(fā)現(xiàn)這些代碼,在網(wǎng)上花時間查找之后找到的解答 . 他們工作的很好,允許各種的排序結(jié)構(gòu). qsort 傳送 4 個參數(shù). 第一個參數(shù)指向物體數(shù)組 (被排序的數(shù)組d). 第二個參數(shù)是我們想排序數(shù)組的個數(shù)... 當(dāng)然,我們想所有的排序的物體普遍的被顯示(各個level). 第三個參數(shù)規(guī)定物體結(jié)構(gòu)的大不, 第四個參數(shù)指向我們的 Compare() 函數(shù).

            大概有更好的排序結(jié)構(gòu)的方法, 但是 qsort() 工作起來... 快速方便,簡單易用!

            這個是重要的知識點(diǎn), 若你們想用 glAlphaFunc() 和 glEnable(GL_ALPHA_TEST), 排序是沒必要的. 然而, 用Alpha 功能你被限制在完全透明或完全白底混合, 沒有中間值. 用 Blendfunc()排序用一些更多的工作,但他顧及半透明物體.

             
              

            // 排序物體從距離:我們物體數(shù)組的開始地址 *** MSDN 代碼修改為這個 TUT ***// 各種的數(shù)按// 各自的要素的// 指針比較的函數(shù)
                qsort((void *) &object, level, sizeof(struct objects), (compfn)Compare );
            }

              
             初始化的代碼總是一樣的. 首先的現(xiàn)兩行取得我們window 的消息和我們建盤消息. 然后我們用 srand() 建一個基于時間的多樣化的游戲. 之后我們調(diào)入 TGA 圖片并用LoadTGA()轉(zhuǎn)換到材質(zhì) . 先前的 5個圖片是將穿過屏幕的物體. Explode 是我們爆炸動畫, 大地和天空 彌補(bǔ)現(xiàn)場背景, crosshair是你在屏幕上看到表現(xiàn)鼠標(biāo)當(dāng)前位置的十字光標(biāo), 最后, 用來顯示分?jǐn)?shù),標(biāo)題和士氣值的字體的圖片. 若任何調(diào)入圖片的失誤,則到返回 FALSE 值, 并程序結(jié)束. 值得注意的是這些基本代碼不是返回整數(shù)型(INIT)的 FAILED 錯誤消息.
             
              

            BOOL Initialize (GL_Window* window, Keys* keys)                // 任何 OpenGL 從這初始化
            {
                g_window    = window;
                g_keys        = keys;

                srand( (unsigned)time( NULL ) );                    // 使隨機(jī)化事件

                if ((!LoadTGA(&textures[0],"Data/BlueFace.tga")) ||            // 調(diào)入藍(lán)面材質(zhì)
                    (!LoadTGA(&textures[1],"Data/Bucket.tga")) ||            // 調(diào)入水桶材質(zhì)
                    (!LoadTGA(&textures[2],"Data/Target.tga")) ||            // 調(diào)入靶子材質(zhì)
                    (!LoadTGA(&textures[3],"Data/Coke.tga")) ||            // 調(diào)入 可樂材質(zhì)
                    (!LoadTGA(&textures[4],"Data/Vase.tga")) ||            // 調(diào)入 花瓶 材質(zhì)
                    (!LoadTGA(&textures[5],"Data/Explode.tga")) ||            // 調(diào)入 爆炸材質(zhì)
                    (!LoadTGA(&textures[6],"Data/Ground.tga")) ||            // 調(diào)入 地面 材質(zhì)
                    (!LoadTGA(&textures[7],"Data/Sky.tga")) ||            // 調(diào)入 天空 材質(zhì)
                    (!LoadTGA(&textures[8],"Data/Crosshair.tga")) ||        // 調(diào)入 十字光標(biāo) 材質(zhì)
                    (!LoadTGA(&textures[9],"Data/Font.tga")))            // 調(diào)入 字符 材質(zhì)
                {
                    return FALSE;                        // 若調(diào)入失敗, 返回錯誤
                }

              
             若所有圖片調(diào)入成功則輪到材質(zhì), 我們能繼續(xù)初始化. 字體材質(zhì)被調(diào)入, 因而保險(xiǎn)能建立我們的字體. 我們跳入BuildFont()來做這些.
            然后我們設(shè)置OpenGL. 背景色為黑, alpha 也設(shè)為0.0f. 深度緩沖區(qū)設(shè)為激活小于或等于測試.

            glBlendFunc() 是很重要的一行代碼. 我們設(shè)混合函數(shù)(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA). 這些加上alpha變量的屏幕上的混合物體存在物體的材質(zhì). 在設(shè)置混合模式之后, 我們激活blending(混合). 然后我們打開 2D 材質(zhì)貼圖, 最后,打開 GL_CULL_FACE. 這是去除每個物體的后面( 沒有一點(diǎn)浪費(fèi)在一些我們看不到的循環(huán) ). 畫一些四邊形逆時針卷動 ,因而精致而適當(dāng)?shù)拿嫫?

            早先的教程我談?wù)撌褂胓lAlphaFunc()代替alpha 混合. 若你想用Alpha 函數(shù), 注釋出的兩行混合代碼和不注釋的兩行在glEnable(GL_BLEND)之下. 你也能注釋出qsort()函數(shù)在 InitObject() 部分里的代碼.

            程序應(yīng)該運(yùn)行ok,但sky 材質(zhì)將不在這. 因?yàn)閟ky的材質(zhì)已是一個alpha 變量0.5f. 當(dāng)早在我說關(guān)于Alpha函數(shù), 我提及它只工作在alpha 變量0 或 1. 若你想它出現(xiàn),你將不得不修改sky的材質(zhì)alpha 通道! 再則, 若你決定用Alpha 函數(shù)代替, 你不得排序物體.兩個方法都有好處! 再下而是從SGI 網(wǎng)站的快速引用:

            "alpha 函數(shù)丟棄細(xì)節(jié),代替畫他們在結(jié)構(gòu)緩沖器里. 因此排序原來的物體不是必須的 (除了一些其它像混合alpha模式是打開的). 不占優(yōu)勢的是象素必須完全白底或完全透明".



             
              

                BuildFont();                                // 建立我們的字體顯示列表

                glClearColor(0.0f, 0.0f, 0.0f, 0.0f);                    // 黑色背景
                glClearDepth(1.0f);                            // 安裝深度緩沖器
                glDepthFunc(GL_LEQUAL);                            // 深度的類型測試
                glEnable(GL_DEPTH_TEST);                            // 打開深度測試
                glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);                // 打開 Alpha 混合
                glEnable(GL_BLEND);                            // 打開混合
                glAlphaFunc(GL_GREATER,0.1f);                        // 設(shè) Alpha 測試
                glEnable(GL_ALPHA_TEST);                            // 打開 Alpha 測試
                glEnable(GL_TEXTURE_2D);                            // 打開材質(zhì)貼圖
                glEnable(GL_CULL_FACE);                            // 去掉畫物體的背面

              
             在程序的這段, 還沒有物體被定義,所以循環(huán)30個物體,每個物體都調(diào)InitObject(). 
              

                for (int loop=0; loop<30; loop++)                    // 循環(huán)在 30 個物體Objects
                    InitObject(loop);                        // 初始化每個物體

                return TRUE;                            // 返回正確 (設(shè)初值成功)
            }

              
             在初始化代碼里, 調(diào)入BuildFont() 建立95 的顯示列表. 所以這里在程序結(jié)束前刪掉95顯示列表 
              

            void Deinitialize (void)                            // 任何user 結(jié)束初始化從這
            {
                glDeleteLists(base,95);                            // 刪掉所有95 字體顯示列表
            }

              
             現(xiàn)在為急速原始物體... 是實(shí)際被選?形鍰宓拇?. 第一行為我們選擇物體的信息分配內(nèi)存. hits 是當(dāng)選擇時碰撞迅檢測的次數(shù).
             
              

            void Selection(void)                                // 這是選擇正確
            {
                GLuint    buffer[512];                            //  設(shè)選擇緩沖
                GLint    hits;                                // 選擇物體的數(shù)

              
             下面的代碼, 若游戲結(jié)束(FALSE).沒有選任何, 返回(exit). 若游戲還在運(yùn)行 (TRUE),用Playsound() 命令放射擊的聲間. 僅僅調(diào)Selection()的時間是在當(dāng)已鼠標(biāo)按下時和每次按下按鍵調(diào)用時, 想放射擊的聲音. 聲音在放在 async 模式 ,所以放音樂是程序不會停.  
              

                if (game)                                // 游戲是否結(jié)束?
                    return;                            // 是,返回, 不在檢測 Hits
               
                PlaySound("data/shot.wav",NULL,SND_ASYNC);                // 放音樂 Gun Shot

              
             設(shè)視點(diǎn). viewport[] 包括當(dāng)前 x, y, 當(dāng)前的視點(diǎn)(OpenGL Window)長度,寬度.

            glGetIntegerv(GL_VIEWPORT, viewport) 取當(dāng)前視點(diǎn)存在viewport[]. 最初,等于 OpenGL 窗口維數(shù). glSelectBuffer(512, buffer) 說 OpenGL 用這個內(nèi)存.
             
              

                // 視點(diǎn)的大小. [0] 是 <x>, [1] 是 <y>, [2] 是 <length>, [3] 是 <width>
                GLint    viewport[4];

                // 這是設(shè)視點(diǎn)的數(shù)組在屏幕窗口的位置
                glGetIntegerv(GL_VIEWPORT, viewport);
                glSelectBuffer(512, buffer);                        // 告訴 OpenGL 使我們的數(shù)組來選擇

              
             存opengl的模式. 在這個模式什么也不畫. 代替, 在選擇模式物體渲染信息存在緩存.
            下面初實(shí)化name 堆棧,通過調(diào)入glInitNames() 和glPushName(0). I它重要的是標(biāo)記若程序不在選擇模式, 一個到glPushName()調(diào)用將忽略. 當(dāng)然在選擇的模試, 但這一些是是緊記的.

             
              

                // 設(shè) OpenGL 選擇模式. 將不畫東西. 物體 ID’的廣度放在內(nèi)存
                (void) glRenderMode(GL_SELECT);

                glInitNames();                                // 設(shè)名字堆棧
                glPushName(0);                                // Push 0 (最少一個) 在棧上

              
             之后, 不得不限制在光標(biāo)的下面畫圖. 為了做這些得用到投影矩陣. 然后把它推到堆棧中.重設(shè)矩陣則用到 glLoadIdentity().
            用gluPickMatrix()限制的畫. 第1個參數(shù)是當(dāng)前鼠標(biāo)的 x-座標(biāo), 第2個參數(shù)是當(dāng)前鼠標(biāo)的 y-座標(biāo), 然后寬和高的選區(qū). 最后當(dāng)前的 viewport[]. viewport[] 是指出視點(diǎn)的邊界. x 和_y 將在選區(qū)的中心.

             
              

                glMatrixMode(GL_PROJECTION);                        // 選投影矩陣
                glPushMatrix();                                // 壓入投影矩陣
                glLoadIdentity();                                // 重設(shè)矩陣

                //  這是建一個矩陣使鼠標(biāo)在屏幕縮放
                gluPickMatrix((GLdouble) mouse_x, (GLdouble) (viewport[3]-mouse_y), 1.0f, 1.0f, viewport);

              
             調(diào)入 gluPerspective() 應(yīng)用透視矩陣 ,被gluPickMatrix()選擇矩陣限制所畫區(qū)域 .
            打開modelview 矩陣,調(diào)用DrawTargets()畫我們的靶子. 畫靶子在DrawTargets() 而不在 Draw() 是因?yàn)閮H僅想選擇物體的碰撞檢測且, 不是天空,大地,光標(biāo).

            之后, 打開回到發(fā)射矩陣, 從堆棧中彈出矩陣. 之扣打開回到modelview 矩陣.

            最后一行,回到渲染模式 因而物體畫的很真實(shí)的在屏幕上. hits 將采集gluPickMatrix()所需要取渲染的物體數(shù) .

             
              

                // 應(yīng)用透視矩陣
                gluPerspective(45.0f, (GLfloat) (viewport[2]-viewport[0])/(GLfloat) (viewport[3]-viewport[1]), 0.1f, 100.0f);
                glMatrixMode(GL_MODELVIEW);                            // 選擇模型變換矩陣
                DrawTargets();                                // 畫目標(biāo)
                glMatrixMode(GL_PROJECTION);                        // 選擇投影變換矩陣
                glPopMatrix();                                // 取出投影矩陣
                glMatrixMode(GL_MODELVIEW);                            // 選模式顯示矩陣
                hits=glRenderMode(GL_RENDER);                        // 切換模式, 找出有多少

              
             檢查若多于0 個hits 記錄. 若這樣, 設(shè)choose 為 第一個物體的名子. depth 取得它有多遠(yuǎn).
            每個hit 分有4 個項(xiàng)目在內(nèi)存. 第一,在名子堆棧上打擊發(fā)生時的數(shù)字 .第二, 所選物體的最小z值. 第三,所選物體的最大 z 值, 最后,在同一時間里所選物體名子堆棧的內(nèi)容 (物體的名子). 在這一課,我們僅對最小z值和物體名子感興趣.

             
              

                if (hits > 0)                                // 若有大于0個 Hits
                {
                    int    choose = buffer[3];                    // 選擇第一物體
                    int    depth = buffer[1];                        // 存它有多遠(yuǎn)
              
             
            做循環(huán)所有hits 使沒有物體在第一個物體旁邊. 否則, 兩個物體會重疊, 一個物體碰到另一個.當(dāng)你射擊時, 重疊的物體會被誤選. 
              

                    for (int loop = 1; loop < hits; loop++)                // 循環(huán)所有檢測到的物體
                    {
                        // 對于其它的物體
                        if (buffer[loop*4+1] < GLuint(depth))
                        {
                            choose = buffer[loop*4+3];                // 選擇更近的物體
                            depth = buffer[loop*4+1];                // 保存它有多遠(yuǎn)
                        }
                    }

              
             若物體被選.
             
              

                    if (!object[choose].hit)                    // 如果物體還沒有被擊中
                    {
                        object[choose].hit=TRUE;                // 標(biāo)記物體象被擊中
                        score+=1;                        // 增加分?jǐn)?shù)
                        kills+=1;                        // 加被殺數(shù)

              
             如下
             
              

                        if (kills>level*5)                    // 已有新的級?
                        {
                            miss=0;                    // 失掉數(shù)回0
                            kills=0;                    // 設(shè) Kills數(shù)為0
                            level+=1;                    // 加 Level
                            if (level>30)                // 高過 30?
                                level=30;                // 設(shè) Level 為 30 (你是 God 嗎?)
                        }
                    }
                }
            }

              
             如下
             
              

            void Update(DWORD milliseconds)                            // 這里用來更新
            {
                if (g_keys->keyDown[VK_ESCAPE])                        // 按下 ESC?
                {
                    TerminateApplication (g_window);                    // 推出程序
                }

              
             如下  
              

                if (g_keys->keyDown[' '] && game)                    // 按下空格鍵?
                {
                    for (int loop=0; loop<30; loop++)                // 循環(huán)所有的物體
                        InitObject(loop);                    // 初始化

                    game=FALSE;                        //設(shè)game為false
                    score=0;                            // 分?jǐn)?shù)為0
                    level=1;                            // 級別為1
                    kills=0;                            // 殺敵數(shù)為0
                    miss=0;                            // 漏過數(shù)為0
                }

                if (g_keys->keyDown[VK_F1])                        // 按下f1?
                {
                    ToggleFullscreen (g_window);                // 換到全屏模式
                }

                roll-=milliseconds*0.00005f;                    // 云的旋轉(zhuǎn)

                for (int loop=0; loop<level; loop++)                    // 循環(huán)所有的物體
                {

              
             下面的代碼按物體的運(yùn)動方向更新所有的運(yùn)動 
              

                    if (object[loop].rot==1)                   
                        object[loop].spin-=0.2f*(float(loop+milliseconds));    // 若順時針,則順時針旋轉(zhuǎn)

                    if (object[loop].rot==2)
                        object[loop].spin+=0.2f*(float(loop+milliseconds));    // 若逆時針,則逆時針旋轉(zhuǎn)

                    if (object[loop].dir==1)                   
                        object[loop].x+=0.012f*float(milliseconds);        // 向右移動

                    if (object[loop].dir==0)                   
                        object[loop].x-=0.012f*float(milliseconds);        // 向左移動

                    if (object[loop].dir==2)                   
                        object[loop].y+=0.012f*float(milliseconds);        // 向上移動

                    if (object[loop].dir==3)                   
                        object[loop].y-=0.0025f*float(milliseconds);        // 向下移動

              
             下面的代碼處理當(dāng)物體移動到邊緣處,如果你沒有擊中它的結(jié)果 
              

                    // 如果到達(dá)左邊界,你沒有擊中,則增加丟失的目標(biāo)數(shù)
                    if ((object[loop].x<(object[loop].distance-15.0f)/2.0f) && (object[loop].dir==0) && !object[loop].hit)
                    {
                        miss+=1;                       
                        object[loop].hit=TRUE;                   
                    }

                    // 如果到達(dá)右邊界,你沒有擊中,則增加丟失的目標(biāo)數(shù)
                    if ((object[loop].x>-(object[loop].distance-15.0f)/2.0f) && (object[loop].dir==1) && !object[loop].hit)
                    {
                        miss+=1;                       
                        object[loop].hit=TRUE;               
                    }

                    // 如果到達(dá)下邊界,你沒有擊中,則增加丟失的目標(biāo)數(shù)
                    if ((object[loop].y<-2.0f) && (object[loop].dir==3) && !object[loop].hit)
                    {
                        miss+=1;                       
                        object[loop].hit=TRUE;                   
                    }

                    //如果到達(dá)左邊界,你沒有擊中,則方向變?yōu)橄蛳?br>        if ((object[loop].y>4.5f) && (object[loop].dir==2))       
                        object[loop].dir=3;               
                }
            }

              
             下面的代碼在屏幕上繪制一個圖像 
              

            void Object(float width,float height,GLuint texid)                // 畫物體用需要的寬,高,材質(zhì)
            {
                glBindTexture(GL_TEXTURE_2D, textures[texid].texID);            // 選合適的材質(zhì)
                glBegin(GL_QUADS);                            // 開始畫四邊形
                    glTexCoord2f(0.0f,0.0f); glVertex3f(-width,-height,0.0f);   
                    glTexCoord2f(1.0f,0.0f); glVertex3f( width,-height,0.0f);   
                    glTexCoord2f(1.0f,1.0f); glVertex3f( width, height,0.0f);   
                    glTexCoord2f(0.0f,1.0f); glVertex3f(-width, height,0.0f);   
                glEnd();                               
            }

              
             下面的代碼繪制爆炸的效果 
              

                void Explosion(int num)                        // 畫爆炸動畫的1幀
            {
                float ex = (float)((object[num].frame/4)%4)/4.0f;            // 計(jì)算爆炸時生成的x的紋理坐標(biāo)
                float ey = (float)((object[num].frame/4)/4)/4.0f;            // 計(jì)算爆炸時生成的y的紋理坐標(biāo)

                glBindTexture(GL_TEXTURE_2D, textures[5].texID);            // 選擇爆炸的紋理
                glBegin(GL_QUADS);                           
                    glTexCoord2f(ex      ,1.0f-(ey      )); glVertex3f(-1.0f,-1.0f,0.0f);   
                    glTexCoord2f(ex+0.25f,1.0f-(ey      )); glVertex3f( 1.0f,-1.0f,0.0f);   
                    glTexCoord2f(ex+0.25f,1.0f-(ey+0.25f)); glVertex3f( 1.0f, 1.0f,0.0f);
                    glTexCoord2f(ex      ,1.0f-(ey+0.25f)); glVertex3f(-1.0f, 1.0f,0.0f);   
                glEnd();                               
              
             增加幀數(shù),如果大于63,則重置動畫 
              

                object[num].frame+=1;                        // 加當(dāng)前的爆炸動畫幀
                if (object[num].frame>63)                        // 是否已完成所有的16幀?
                {
                    InitObject(num);                        // 定義物體 (給新的變量)
                }
            }

              
             畫靶子 
              

            void DrawTargets(void)                                // 畫靶子
            {
                glLoadIdentity();                           
                glTranslatef(0.0f,0.0f,-10.0f);                        // 移入屏幕 20 個單位
                for (int loop=0; loop<level; loop++)                        // 循環(huán)在 9 個物體
                {

                    glLoadName(loop);                            // 給物體新名字
                    glPushMatrix();                            // 存矩陣
                    glTranslatef(object[loop].x,object[loop].y,object[loop].distance);    // 物體的位置 (x,y)

                    if (object[loop].hit)                        // 若物體已被點(diǎn)擊
                    {
                        Explosion(loop);                        // 畫爆炸動畫
                    }
                    else                               
                    {
                        glRotatef(object[loop].spin,0.0f,0.0f,1.0f);            // 旋轉(zhuǎn)物體
                        Object(size[object[loop].texid].w,size[object[loop].texid].h,object[loop].texid);    // 畫物體
                    }
                    glPopMatrix();                            // 彈出矩陣
                }
            }

              
             下面的代碼繪制整個場景 
              

            void Draw(void)                                // 畫我們的現(xiàn)場
            {
                glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);            // 清除屏幕和深度緩沖
                glLoadIdentity();                            // 重設(shè)矩陣

              
             下面的代碼繪制飄動的天空,它由四塊紋理組成,每一塊的移動速度都不一樣,并把它們混合起來 
              

                glPushMatrix();                               
                glBindTexture(GL_TEXTURE_2D, textures[7].texID);            // 選天空的材質(zhì)
                glBegin(GL_QUADS);                       
                    glTexCoord2f(1.0f,roll/1.5f+1.0f); glVertex3f( 28.0f,+7.0f,-50.0f);   
                    glTexCoord2f(0.0f,roll/1.5f+1.0f); glVertex3f(-28.0f,+7.0f,-50.0f);   
                    glTexCoord2f(0.0f,roll/1.5f+0.0f); glVertex3f(-28.0f,-3.0f,-50.0f);   
                    glTexCoord2f(1.0f,roll/1.5f+0.0f); glVertex3f( 28.0f,-3.0f,-50.0f);   

                    glTexCoord2f(1.5f,roll+1.0f); glVertex3f( 28.0f,+7.0f,-50.0f);       
                    glTexCoord2f(0.5f,roll+1.0f); glVertex3f(-28.0f,+7.0f,-50.0f);       
                    glTexCoord2f(0.5f,roll+0.0f); glVertex3f(-28.0f,-3.0f,-50.0f);       
                    glTexCoord2f(1.5f,roll+0.0f); glVertex3f( 28.0f,-3.0f,-50.0f);       
                    glTexCoord2f(1.0f,roll/1.5f+1.0f); glVertex3f( 28.0f,+7.0f,0.0f);   
                    glTexCoord2f(0.0f,roll/1.5f+1.0f); glVertex3f(-28.0f,+7.0f,0.0f);   
                    glTexCoord2f(0.0f,roll/1.5f+0.0f); glVertex3f(-28.0f,+7.0f,-50.0f);   
                    glTexCoord2f(1.0f,roll/1.5f+0.0f); glVertex3f( 28.0f,+7.0f,-50.0f);   

                    glTexCoord2f(1.5f,roll+1.0f); glVertex3f( 28.0f,+7.0f,0.0f);       
                    glTexCoord2f(0.5f,roll+1.0f); glVertex3f(-28.0f,+7.0f,0.0f);       
                    glTexCoord2f(0.5f,roll+0.0f); glVertex3f(-28.0f,+7.0f,-50.0f);       
                    glTexCoord2f(1.5f,roll+0.0f); glVertex3f( 28.0f,+7.0f,-50.0f);       
                glEnd();                           
              
             下面的代碼繪制地面 
              

                glBindTexture(GL_TEXTURE_2D, textures[6].texID);            // 大地材質(zhì)
                glBegin(GL_QUADS);                           
                    glTexCoord2f(7.0f,4.0f-roll); glVertex3f( 27.0f,-3.0f,-50.0f);   
                    glTexCoord2f(0.0f,4.0f-roll); glVertex3f(-27.0f,-3.0f,-50.0f);   
                    glTexCoord2f(0.0f,0.0f-roll); glVertex3f(-27.0f,-3.0f,0.0f);   
                    glTexCoord2f(7.0f,0.0f-roll); glVertex3f( 27.0f,-3.0f,0.0f);   
                glEnd();                               
              
             繪制我們的靶子 
              

                DrawTargets();                                // 畫我們的靶子
                glPopMatrix();                               
              
             下面的代碼繪制我們的十字光標(biāo)
             
              

                // 十字光標(biāo) (在光標(biāo)里)
                RECT window;                                // 用來存窗口位置
                GetClientRect (g_window->hWnd,&window);                    // 取窗口位置
                glMatrixMode(GL_PROJECTION);                       
                glPushMatrix();                               
                glLoadIdentity();                       
                glOrtho(0,window.right,0,window.bottom,-1,1);                // 設(shè)置為正投影
                glMatrixMode(GL_MODELVIEW);                       
                glTranslated(mouse_x,window.bottom-mouse_y,0.0f);            // 移動到當(dāng)前鼠標(biāo)位置
                Object(16,16,8);                            // 畫十字光標(biāo)

              
             下面的代碼用來顯示幫助文字 
              

                // 游戲狀態(tài) / 標(biāo)題名稱
                glPrint(240,450,"NeHe Productions");                    // 輸出 標(biāo)題名稱
                glPrint(10,10,"Level: %i",level);                    // 輸出 等級
                glPrint(250,10,"Score: %i",score);                    // 輸出 分?jǐn)?shù)

              
             如果丟失10個物體,游戲結(jié)束 
              

                if (miss>9)                                // 我們已丟失 10 個物體?
                {
                    miss=9;                                // 限制丟失是10個
                    game=TRUE;                            // 游戲結(jié)束
                }

              
             在下面的代碼里, 我們查看若game 是TRUE. 若 game 是TRUE, 我們輸出 ’GAME OVER’游戲結(jié)束的消息. 若game 是false, 我們輸出 玩家的士氣morale (到10溢出). 士氣morale是被設(shè)計(jì)用來從10減去玩家失誤的次數(shù)(miss) . 玩家失掉的越多, 士氣越低.
             
              

                if (game)                                // 游戲是否結(jié)束?
                    glPrint(490,10,"GAME OVER");                // 結(jié)束消息
                else
                    glPrint(490,10,"Morale: %i/10",10-miss);            // 輸出剩余生命
              
             最后做的事我們選投影矩陣, 恢復(fù)(取出) 我們的矩陣返回到前一個情形, 設(shè)矩陣模式為 modelview ,刷新緩沖區(qū) ,使所有物體被渲染.  
              

                glMatrixMode(GL_PROJECTION);                       
                glPopMatrix();                               
                glMatrixMode(GL_MODELVIEW);                       

                glFlush();                               
            }

              
             這課程是多次熬夜的成果, 許多的時間用來編碼和寫 HTML. 在這一課結(jié)束的時候你應(yīng)你會學(xué)會怎樣picking, sorting, alpha blending and alpha testing 工作. 制做點(diǎn)和軟件. 每一個游戲, 到精選的GUI’們.最好的未來是制做時你不用記錄物體. 你給一個名字和碰撞 . 這很簡單! 用alpha 通道和alpha 測試你能使物體完全顯示, 或漏出一些. 結(jié)果是很好, 你不用擔(dān)心關(guān)于顯示物體的材質(zhì), 除非你不顯示他們! 同以往一樣, 我希望你喜歡這個課程,愿看到一些好的游戲或好的項(xiàng)目從這個課程誕生.如果你有什么問題或找到錯誤,讓我知道 ... 我僅是一個普通人 :)
            我將花大量的時間加入東西像物理系統(tǒng), 更多圖, 更多聲音, 等. 雖然只是一個課程! 我不寫不按車燈和車輪. 我寫這個用盡量不混亂的方法教你 OpenGL . 我希望看到一些嚴(yán)謹(jǐn)?shù)男薷? 若你找一些cool的課程發(fā)給我一份. 若是好的修改我將放到下載頁. 若有足夠充分的修改我會專注修改這個課程的版本! 我在這里給你一個起點(diǎn). 剩下的靠你了 :)

            要點(diǎn): 這是很重要的,稱為glTexImage2D 你設(shè)為兩種格式國際 GL_RGBA. 否則 alpha blending 將不工作!
             
             
            posted on 2007-12-22 15:11 sdfasdf 閱讀(1504) 評論(0)  編輯 收藏 引用 所屬分類: OPENGL
            国产毛片久久久久久国产毛片| 久久亚洲国产午夜精品理论片| 久久久久亚洲精品男人的天堂| 久久九色综合九色99伊人| 久久久黄色大片| 精品久久久久久国产91| 亚洲一区精品伊人久久伊人| 亚洲中文精品久久久久久不卡| 久久国产精品无码一区二区三区| 国产激情久久久久影院老熟女| 久久精品一本到99热免费| 久久国产精品一区二区| 狠狠色婷婷久久一区二区| 99久久精品免费看国产一区二区三区 | 香蕉久久影院| 久久免费视频网站| 久久夜色精品国产噜噜噜亚洲AV| 久久久久18| 国产精品免费久久久久电影网| 久久久久人妻一区精品性色av| 久久乐国产精品亚洲综合| 国产精品久久久久久一区二区三区| 无码国内精品久久综合88| 久久国产成人午夜AV影院| 欧美激情精品久久久久| 久久人人爽爽爽人久久久| 久久精品aⅴ无码中文字字幕不卡 久久精品成人欧美大片 | 热久久这里只有精品| 久久综合精品国产二区无码| 国产精品久久久久久久久久影院| 免费国产99久久久香蕉| 精品国产乱码久久久久久郑州公司 | 久久久久久综合一区中文字幕 | 久久精品国产亚洲av水果派| 亚洲精品午夜国产va久久| 久久笫一福利免费导航 | 久久一区二区三区99| 久久精品国产99久久丝袜| 久久精品国产久精国产果冻传媒| 99久久精品免费看国产一区二区三区| 日韩久久无码免费毛片软件|