• <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ì)

            搜索

            •  

            積分與排名

            • 積分 - 400065
            • 排名 - 59

            最新評(píng)論

            閱讀排行榜

            評(píng)論排行榜

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

            我確信會(huì)有批評(píng),但我非常樂觀對(duì)這課! 我已在從深度里選擇和排序物體這個(gè)主題里找到快樂!

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

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

            如以往我希望你喜歡這課程. 我感興趣你對(duì)他的想法. 若你有些問題或你發(fā)現(xiàn)一些問題,告訴我. 我匆忙的完成這課程 所以若你發(fā)現(xiàn)哪部分很難懂,給我發(fā)些郵件,然后我會(huì)用不同的方式或更詳細(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). 移下到 對(duì)象/庫 模塊 加入 OpenGL32.lib, GLu32.lib 和 GLaux.lib. 預(yù)編譯一個(gè)需要的庫的失敗將使編譯器找出所出的錯(cuò)誤. 有時(shí)你不想發(fā)生! 使事情更壞, 若你僅僅預(yù)編譯庫在debug 模式, 和有人試在release 模式建立你程序... 更多的錯(cuò)誤. 有許多人看代碼. 他們大多數(shù)是新程序員. 他們?nèi)〉侥愕拇a, 試著編譯. 他們得到錯(cuò)誤, 刪掉代碼,移走.
            下而的代碼告訴編譯者去連接需要的庫. 一點(diǎn)多些的字, 但少些以后的頭痛. 在這個(gè)課程, 我們將連接 OpenGL32 庫,GLu32庫 和 WinMM庫 (用來放音樂). 在這課程我們會(huì)調(diào)入 .TGA 文件,所以我們不用 GLaux庫.

             
              

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

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

             
              

            #ifndef        CDS_FULLSCREEN                           
            #define        CDS_FULLSCREEN 4                       
            #endif                                   

            void DrawTargets();                               

            GL_Window*    g_window;
            Keys*        g_keys;

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

             
              

            // 用戶定義的變量
            GLuint        base;                                // 字體顯示列表
            GLfloat        roll;                                // 旋轉(zhuǎn)的云
            GLint        level=1;                                // 現(xiàn)在的等級(jí)
            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). 這個(gè)結(jié)構(gòu)存了所有一個(gè)物體的信息. 旋轉(zhuǎn)的方向, 若被打中, 在屏幕的位置, 等等.
            一個(gè)快速運(yùn)動(dòng)的變量... rot 我想讓物體旋轉(zhuǎn)特別的方向. hit 若物體沒被打中將是 FALSE . 若物體給打中或飛出, 變量將是 TRUE.

            變量frame 是用來存我們爆炸動(dòng)畫的周期. 每一幀改變?cè)黾右粋€(gè)爆炸材質(zhì). 在這課有更多在不久.

            保存單個(gè)物體的移動(dòng)方向, 我們用變量 dir. 一個(gè)dir 能有4 個(gè)值: 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ì)算屏幕的左右兩邊, 而且在對(duì)象關(guān)閉之前排序物體,畫出物體的距離.



             
              

            struct objects {
                GLuint    rot;                                // 旋轉(zhuǎn) (0-不轉(zhuǎn), 1-順時(shí)針轉(zhuǎn), 2-逆時(shí)針轉(zhuǎn))
                bool    hit;                                // 物體碰撞?
                GLuint    frame;                                // 當(dāng)前爆炸效果的動(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é)果. 我們?cè)谶@課調(diào)入TGA圖代替bitmaps圖片. 下面的用來表示TGA圖片數(shù)據(jù)的結(jié)構(gòu)是盡可能好的 . 若你需要詳細(xì)的解釋下面的代碼,請(qǐng)讀關(guān)于調(diào)入TGA 文件的課程.  
              

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

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

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

            objects    object[30];                            // 定義 30 個(gè)物體

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



             
              

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

            // 每個(gè)物體的大小: 藍(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 通道的. 這個(gè)alpha 通道告訴 OpenGL 哪一部分圖是透明的,哪一部分是白底. alpha 通道是被建立在圖片處理程序, 并保存在.TGA圖片里面. OpenGL 調(diào)入圖片, 能用alpha 通道設(shè)置圖片中每個(gè)象素透明的數(shù)量.

             
              

            bool LoadTGA(TextureImage *texture, char *filename)                    // 調(diào)入一個(gè)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 個(gè)有用的字節(jié)
                GLuint        bytesPerPixel;                        // 每象素字節(jié)數(shù)在 TGA 文件使用
                GLuint        imageSize;                        // 用來圖片大小的存儲(chǔ)
                GLuint        temp;                            // 臨時(shí)變量
                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個(gè)字節(jié)?
                    memcmp(TGAheader,TGAcompare,sizeof(TGAheader))!=0 ||            // 文件頭是不是我們想要的 ?
                    fread(header,1,sizeof(header),file)!=sizeof(header))            // 若正確則讀下 6 個(gè) Bytes
                {
                    if (file == NULL)                            // 文件是否已存在 ?
                        return FALSE;                        // 返回錯(cuò)誤
                    else                                // 否則
                    {
                        fclose(file);                        // 若有任何錯(cuò)誤, 關(guān)掉文件
                        return FALSE;                        // 返回錯(cuò)誤
                    }
                }

                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);                            // 若有任何錯(cuò)誤, 關(guān)掉文件
                    return FALSE;                            // 返回錯(cuò)誤
                }

                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 ||                        // 這個(gè)內(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;                            // 返回錯(cuò)誤
                }

                for(GLuint i=0; i<int(imageSize); i+=bytesPerPixel)                // 在圖象數(shù)據(jù)里循環(huán)
                {                                    // 交換第1和第3 Bytes (’紅’red 和 ’藍(lán)’blue)
                    temp=texture->imageData[i];                        // 臨時(shí)存儲(chǔ) 圖象的 ’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)掉文件

                // 建立一個(gè)貼圖材質(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ì), 你會(huì)看到只有 95 字母計(jì)算空間在圖片頂,左. 第二個(gè)事是你將通知分在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);                // 開始建立一個(gè)列表
                        glBegin(GL_QUADS);                    // 用四邊形組成每個(gè)字母
                            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();                        // 完成建軍立這個(gè)顯示列表
                }                                // 循環(huán)直到所有 256 完成建立
            }

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

            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)用排序程序. 它比較距離在兩個(gè)結(jié)構(gòu)并返回-1 若第一個(gè)結(jié)構(gòu)的距離小于第二個(gè) , 1 i若 第一個(gè)結(jié)構(gòu)的距離大于第二個(gè) 0 否則 (若 距離相等)  
              

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

              
             InitObject() 代碼是來建立每個(gè)物體. 我們開始設(shè) rot 為 1. 這使物體順時(shí)針旋轉(zhuǎn). 然后設(shè)爆炸效果動(dòng)畫幀為0(我們不想爆炸效果從中間開始).我們下面設(shè) hit 為 FALSE, 意思是物體還沒被擊中或正開如. 選一個(gè)物體材質(zhì), texid 用來給一個(gè)隨機(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 個(gè)單位. 所以當(dāng)物體在畫時(shí), 他們將畫從-10.0f to -50.0f 單位 在屏幕(不挨著, 也不離得太遠(yuǎn)). 我分隨機(jī)數(shù)為 100.0f 得到更精確的浮點(diǎn)數(shù)值.

            在給完隨機(jī)的距離之后, 我們給物體一個(gè)隨機(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) 這是最高級(jí).

            選一個(gè)方向.

            使事情簡(jiǎn)單明白x, 寫一個(gè)快的例子. 距離是 -30.0f ,當(dāng)前級(jí)是 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 個(gè)單位 , 距離是 -30.0f. 其實(shí)是 -40.0f.用透視的代碼在 NeHeGL.cpp 文件.


             
              

            GLvoid InitObject(int num)                            // 初始化一個(gè)物體
            {
                object[num].rot=1;                            // 順時(shí)針旋轉(zhuǎn)
                object[num].frame=0;                        // 設(shè)爆炸效果動(dòng)畫幀為0
                object[num].hit=FALSE;                        // 設(shè)點(diǎn)擊檢測(cè)為0
                object[num].texid=rand()%5;                        // 設(shè)一個(gè)材質(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ī)的延時(shí)量 (確定變量)
                object[num].x=((object[num].distance-15.0f)/2.0f)-(5*level)-float(rand()%(5*level));
                object[num].dir=(rand()%2);                        // 選一個(gè)隨機(jī)的方向

              
             檢查方向
             
              

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

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

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

              
             下面檢查若texid 是 1. 這樣, 電腦所選物體的是 Bucket. bucket不從左到右運(yùn)動(dòng), 它從天上掉下來. 首先我們不得不設(shè) dir 是 3. 這告訴電腦我們的水桶bucket 是掉下來或向下運(yùn)動(dòng).
            我們最初的代碼假定物體從左到右運(yùn)動(dòng). 因?yàn)閎ucket 是向下落的, 我們得不給它一個(gè)新的隨機(jī)的變量 x . 若不是這樣, bucket 會(huì)被看不到. 它將不在左邊落下就在屏幕外面. 我們給它一個(gè)新的隨機(jī)距離變量在屏幕上. 代替減去15, 我們僅僅減去 10. 這給我們一些幅度, 保持物體在屏幕??. 設(shè)我們的distance 是-30.0f, 從0.0f -40.0f的隨機(jī)變量. 為什么從 0.0f 到 40.0f? 不是從0.0f to -40.0f? 答案很簡(jiǎn)單. rand() 函數(shù)總返回正數(shù). 所以總是正數(shù). 另外,回到我們的故事. 我們有個(gè)正數(shù) 從0.0f 到 40.0f.我們加距離 最小 10.0f 除以 2. 舉個(gè)例子,設(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. 我們想水桶從天上下來. 我人不想穿過云. 所以我們?cè)O(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 (在地下). 然后減一個(gè)值從0.0f 到 5 乘當(dāng)前 level. 靶子不是立即出現(xiàn). 在高級(jí)別是有延時(shí), 通過delay, 靶子將出現(xiàn)在一個(gè)在另一個(gè)以后, 給你很少時(shí)間打到他們.

             
              

                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)處的物體是先畫的,這是非常重要的, 下面畫緊臨的上面的物體.

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

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

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

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

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

             
              

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

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

            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)入失敗, 返回錯(cuò)誤
                }

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

            glBlendFunc() 是很重要的一行代碼. 我們?cè)O(shè)混合函數(shù)(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA). 這些加上alpha變量的屏幕上的混合物體存在物體的材質(zhì). 在設(shè)置混合模式之后, 我們激活blending(混合). 然后我們打開 2D 材質(zhì)貼圖, 最后,打開 GL_CULL_FACE. 這是去除每個(gè)物體的后面( 沒有一點(diǎn)浪費(fèi)在一些我們看不到的循環(huán) ). 畫一些四邊形逆時(shí)針卷動(dòng) ,因而精致而適當(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ì)已是一個(gè)alpha 變量0.5f. 當(dāng)早在我說關(guān)于Alpha函數(shù), 我提及它只工作在alpha 變量0 或 1. 若你想它出現(xiàn),你將不得不修改sky的材質(zhì)alpha 通道! 再則, 若你決定用Alpha 函數(shù)代替, 你不得排序物體.兩個(gè)方法都有好處! 再下而是從SGI 網(wǎng)站的快速引用:

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



             
              

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

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

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

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

                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í)碰撞迅檢測(cè)的次數(shù).
             
              

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

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

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

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

            glGetIntegerv(GL_VIEWPORT, viewport) 取當(dāng)前視點(diǎn)存在viewport[]. 最初,等于 OpenGL 窗口維數(shù). glSelectBuffer(512, buffer) 說 OpenGL 用這個(gè)內(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的模式. 在這個(gè)模式什么也不畫. 代替, 在選擇模式物體渲染信息存在緩存.
            下面初實(shí)化name 堆棧,通過調(diào)入glInitNames() 和glPushName(0). I它重要的是標(biāo)記若程序不在選擇模式, 一個(gè)到glPushName()調(diào)用將忽略. 當(dāng)然在選擇的模試, 但這一些是是緊記的.

             
              

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

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

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

             
              

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

                //  這是建一個(gè)矩陣使鼠標(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僅想選擇物體的碰撞檢測(cè)且, 不是天空,大地,光標(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 個(gè)hits 記錄. 若這樣, 設(shè)choose 為 第一個(gè)物體的名子. depth 取得它有多遠(yuǎn).
            每個(gè)hit 分有4 個(gè)項(xiàng)目在內(nèi)存. 第一,在名子堆棧上打擊發(fā)生時(shí)的數(shù)字 .第二, 所選物體的最小z值. 第三,所選物體的最大 z 值, 最后,在同一時(shí)間里所選物體名子堆棧的內(nèi)容 (物體的名子). 在這一課,我們僅對(duì)最小z值和物體名子感興趣.

             
              

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

                    for (int loop = 1; loop < hits; loop++)                // 循環(huán)所有檢測(cè)到的物體
                    {
                        // 對(duì)于其它的物體
                        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)                    // 已有新的級(jí)?
                        {
                            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;                            // 級(jí)別為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)動(dòng)方向更新所有的運(yùn)動(dòng) 
              

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

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

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

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

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

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

              
             下面的代碼處理當(dāng)物體移動(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;               
                }
            }

              
             下面的代碼在屏幕上繪制一個(gè)圖像 
              

            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)                        // 畫爆炸動(dòng)畫的1幀
            {
                float ex = (float)((object[num].frame/4)%4)/4.0f;            // 計(jì)算爆炸時(shí)生成的x的紋理坐標(biāo)
                float ey = (float)((object[num].frame/4)/4)/4.0f;            // 計(jì)算爆炸時(shí)生成的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,則重置動(dòng)畫 
              

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

              
             畫靶子 
              

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

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

                    if (object[loop].hit)                        // 若物體已被點(diǎn)擊
                    {
                        Explosion(loop);                        // 畫爆炸動(dòng)畫
                    }
                    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();                            // 彈出矩陣
                }
            }

              
             下面的代碼繪制整個(gè)場(chǎng)景 
              

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

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

                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)到當(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);                    // 輸出 等級(jí)
                glPrint(250,10,"Score: %i",score);                    // 輸出 分?jǐn)?shù)

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

                if (miss>9)                                // 我們已丟失 10 個(gè)物體?
                {
                    miss=9;                                // 限制丟失是10個(gè)
                    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ù)(取出) 我們的矩陣返回到前一個(gè)情形, 設(shè)矩陣模式為 modelview ,刷新緩沖區(qū) ,使所有物體被渲染.  
              

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

                glFlush();                               
            }

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

            要點(diǎn): 這是很重要的,稱為glTexImage2D 你設(shè)為兩種格式國際 GL_RGBA. 否則 alpha blending 將不工作!
             
             
            posted on 2007-12-22 15:11 sdfasdf 閱讀(1504) 評(píng)論(0)  編輯 收藏 引用 所屬分類: OPENGL
            亚洲精品白浆高清久久久久久| 国产午夜精品理论片久久影视| 国产高潮国产高潮久久久91| 狠狠久久亚洲欧美专区| 久久香蕉国产线看观看乱码| 久久se精品一区二区影院| 亚洲国产成人精品无码久久久久久综合| 久久婷婷色综合一区二区| 久久人妻AV中文字幕| 久久婷婷国产麻豆91天堂| 亚洲国产天堂久久综合| 狼狼综合久久久久综合网| 久久精品二区| 久久影院综合精品| 日批日出水久久亚洲精品tv| 日韩精品久久久久久免费| 久久久久亚洲AV成人网| 久久精品国产第一区二区三区| 久久AAAA片一区二区| 久久精品无码午夜福利理论片| 久久综合精品国产一区二区三区| 人妻久久久一区二区三区| 欧美性大战久久久久久| 狠狠色丁香婷婷综合久久来| 国产精品美女久久福利网站| 久久噜噜电影你懂的| 久久久噜噜噜www成人网| 久久人人爽人人爽人人爽 | 99久久99这里只有免费费精品| 日韩AV毛片精品久久久| 久久久久97国产精华液好用吗| 国产亚洲精久久久久久无码| 精品熟女少妇AV免费久久| 手机看片久久高清国产日韩| 久久精品亚洲福利| 午夜不卡888久久| 国产Av激情久久无码天堂| 亚洲精品第一综合99久久| 午夜视频久久久久一区| 久久久久久久尹人综合网亚洲| 99久久夜色精品国产网站|