青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

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

常用鏈接

留言簿(48)

我參與的團隊

搜索

  •  

積分與排名

  • 積分 - 402524
  • 排名 - 59

最新評論

閱讀排行榜

評論排行榜

歡迎來到第21課,在這一課里,你將學會直線,反走樣,正投影,計時,基本的音效和一個簡單的游戲邏輯。希望這里的東西可以讓你高興。我花了兩天的時間寫代碼,并用了兩周的時間寫這份HTML文件,希望你能享受我的勞動。
在這課的結尾你將獲得一個叫"amidar"的游戲,你的任務是走完所有的直線。這個程序有了一個基本游戲的一切要素,關卡,生命值,聲音和一個游戲道具。

我們從第一課的程序來逐步完整這個程序,按照慣例,我們只介紹改動的部分。
 
  

#include    <windows.h>                           
#include    <stdio.h>                           
#include    <stdarg.h>                       
#include    <gl\gl.h>                           
#include    <gl\glu.h>                           
#include    <gl\glaux.h>                           

HDC        hDC=NULL;                           
HGLRC        hRC=NULL;                           
HWND        hWnd=NULL;                           
HINSTANCE    hInstance;                           
  
 bool類型的變量,vline保存了組成我們游戲網(wǎng)格垂直方向上的121條線,上下水平各11條。hline保存了水平方向上的 121條線,用ap來檢查A鍵是否已經(jīng)按下。
當網(wǎng)格被填滿時, filled被設置為TRUE而反之則為FALSE。gameover這個變量的作用顯而易見,當他的值為TRUE時,游戲結束。anti指出抗鋸齒功能是否打開,當設置為TRUE時,該功能是打開著的。active 和 fullscreen 指出窗口是否被最小化以及游戲窗口是窗口模式還是全屏模式。
 
  

bool        keys[256];                           
bool        vline[11][10];                            // 保存垂直方向的11根線條中,每根線條中的10段是否被走過
bool        hline[10][11];                            //保存水平方向的11根線條中,每根線條中的10段是否被走過
bool        ap;                                // A鍵是否已經(jīng)按下
bool        filled;                                // 網(wǎng)格是否被填滿?
bool        gameover;                            // 游戲是否結束?
bool        anti=TRUE;                            // 是否啟用反走樣?
bool        active=TRUE;                           
bool        fullscreen=TRUE;                       
  
 接著設置整型變量。loop1 和 loop2 被用來檢查網(wǎng)格,查看是否有敵人攻擊我們,以及在網(wǎng)格上給對象一個隨機的位置。你將看到loop1 / loop2在后面的程序得到使用。delay 是一個計數(shù)器,我用他來減慢那些壞蛋的動作。當delay的值大于某一個饋值的時候,敵人才可以行動,此時delay將被重置。
adjust是一個非常特殊的變量,即使我們的程序擁有一個定時器,他也僅僅用來檢查你的計算機是否運行地太快。如果是,則需要暫停一下以減慢運行速度。在我地GeForce顯卡上,程序的運行平滑地簡直變態(tài),并且非常非常快。但是在我的PIII/450+Voodoo 3500TV上測試的時候,我注意到程序運行地非常緩慢。我發(fā)現(xiàn)問題在于關于時間控制那部分代碼只能夠用來減慢游戲進行而并不能加速之。因此我引入了一個叫做adjust 的變量。它可以是0到5之間的任何值。游戲中的對象移動速度的不同依賴于這個變量的值。值越小,運動越平滑;而值越大,則運動速度越快。這是在比較慢的機器上運行這個程序最簡單有效的解決方案了。但是請注意,不管對象移動的速度有多快,游戲的速度都不會比我期望的更快。我們推薦把adjust值設置為3,這樣在大部分機器上都有比較滿意的效果。
我們把lives的值設置成5,這樣我們的英雄一出場就擁有5條命。level是一個內部變量,用來指出當前游戲的難度。當然,這并不是你在屏幕上所看到的那個Level。變量level2開始的時候和Level擁有相同的值,但是隨著你技能的提高,這個值也會增加。當你成功通過難度3之后,這個值也將在難度3上停止增加。level 是一個用來表示游戲難度的內部變量,stage才是用來記錄當前游戲關卡的變量。 
  

int        loop1;                                // 通用循環(huán)變量
int        loop2;                                // 通用循環(huán)變量
int        delay;                                // 敵人的暫停時間
int        adjust=3;                            // 調整顯示的速度
int        lives=5;                            // 玩家的生命
int        level=1;                            // 內部游戲的等級
int        level2=level;                            // 顯示的游戲的等級
int        stage=1;                            // 游戲的關卡

  
 接下來我們需要一個結構來記錄游戲中的對象。fx和fy每次在網(wǎng)格上移動我們的英雄和敵人一些較小的象素,以創(chuàng)建一個平滑的動畫效果。x和y則記錄著對象處于網(wǎng)格的那個交點上。
上下左右各有11個點,因此x和y可以是0到10之間的任意值。這也是我們?yōu)槭裁葱枰猣x和fy的原因。考慮如果我們只能夠在上下和左右方向的11個點間移動的話,我們的英雄不得不
在各個點間跳躍前進。這樣顯然是不夠平滑美觀的。
最后一個變量spin用來使對象在Z軸上旋轉。 
  

struct        object                                // 記錄游戲中的對象
{
    int    fx, fy;                                // 使移動變得平滑
    int    x, y;                                // 當前游戲者的位置
    float    spin;                                // 旋轉方向
};

  
 
既然我們已經(jīng)為我們的玩家,敵人,甚至是秘密武器。設置了結構體,那么同樣的,為了表現(xiàn)剛剛創(chuàng)設的結構體的功能和特性,我們也可以為此設置新的結構體。
為我們的玩家創(chuàng)設結構體之下的第一條直線。基本上我們將會為玩家提供fx,fy,x,y和spin值幾種不同的結構體。通過增加這些直線,僅需查看玩家的x值我們就很容易取得玩家的位置,同時我們也可以通過增加玩家的旋轉度來改變玩家的spin值。
第二條直線略有不同。因為同一屏幕我們可以同時擁有至多15個敵人。我們需要為每個敵人創(chuàng)造上面所提到的可變量。我們通過設置一個有15個敵人的組來實現(xiàn)這個目標,如第一個敵人的位置被設定為敵人(0).x.第二個敵人的位置為(1),x等等
第三條直線使得為寶物創(chuàng)設結構體實現(xiàn)了可能。寶物是一個會時不時在屏幕上出現(xiàn)的沙漏。我們需要通過沙漏來追蹤x和y值。但是因為沙漏的位置是固定的所以我們不需要尋找最佳位置,而通過為程序后面的其他物品尋找好的可變量來實現(xiàn)(如fx和fy) 
  

struct    object    player;                                // 玩家信息
struct    object    enemy[9];                            // 最多9個敵人的信息
struct    object    hourglass;                            // 寶物信息

  
 現(xiàn)在我們創(chuàng)建一個描述時間的結構,使用這個結構我們可以很輕松的跟蹤時間變量。
接下來的第一步,就是創(chuàng)建一個64位的頻率變量,它記錄時間的頻率。

resolution變量用來記錄最小的時間間隔。

mm_timer_start和mm_timer_elapsed保存計時器開始時的時間和計時器開始后流失的時間。這兩個變量只有當計算機不擁有performance counter時才啟用。

變量performance_timer用來標識計算機是否有performance counter

如果performance counter啟用,最后兩個變量用來保存計時器開始時的時間和計時器開始后流失的時間,它們比普通的根據(jù)精確。
 
  

struct                                         // 保存時間信息的結構
{
  __int64       frequency;                            // 頻率
  float         resolution;                            // 時間間隔
  unsigned long mm_timer_start;                            // 多媒體計時器的開始時間
  unsigned long mm_timer_elapsed;                        // 多媒體計時器的開始時間
  bool        performance_timer;                        // 使用Performance Timer?
  __int64       performance_timer_start;                    // Performance Timer計時器的開始時間
  __int64       performance_timer_elapsed;                    // Performance Timer計時器的開始時間
} timer;                                   

  
 下一行代碼定義了速度表。如前所說,對象移動的速度依賴于值adjust,而以adjust為下標去檢索速度表,就可以獲得對象的移動速度。 
  

int        steps[6]={ 1, 2, 4, 5, 10, 20 };                // 用來調整顯示的速度

  
 接下來我們將為紋理分配空間。紋理一共2張,一張是背景而另外一張是一張字體紋理。如本系列教程中的其他課程一樣,base用來指出字符顯示列表的基,同樣的我們在最后聲明了窗口過程WndProc()。 
  

GLuint        texture[2];                            // 字符紋理
GLuint        base;                                // 字符顯示列表的開始值

LRESULT    CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);               

  
 接下來會是很有趣的工作。接下來的一段代碼會初始化我們的計時器。代碼會檢查performance counter(非常精確的計數(shù)器)是否可用,如果不可用,則使用多媒體計時器。這段代碼是可以移植的。 
  

void TimerInit(void)                                // 初始化我們的計時器
{
    memset(&timer, 0, sizeof(timer));                    // 清空計時器結構

    // 檢測Performance Counter是否可用,可用則創(chuàng)建
    if (!QueryPerformanceFrequency((LARGE_INTEGER *) &timer.frequency))
    {
        // 如果不可用
        timer.performance_timer    = FALSE;                // 設置Performance Timer為false
        timer.mm_timer_start    = timeGetTime();            // 使用普通的計時器
        timer.resolution    = 1.0f/1000.0f;                // 設置單位為毫秒
        timer.frequency        = 1000;                    // 設置頻率為1000
        timer.mm_timer_elapsed    = timer.mm_timer_start;            // 設置流失的時間為當前的時間
    }

  
 如果performance counter 可用,則執(zhí)行下面的代碼: 
  

    else
    {
        // 使用Performance Counter計時器
        QueryPerformanceCounter((LARGE_INTEGER *) &timer.performance_timer_start);
        timer.performance_timer        = TRUE;                // 設置Performance Timer為TRUE
        // 計算計時的精確度
        timer.resolution        = (float) (((double)1.0f)/((double)timer.frequency));
        // 設置流失的時間為當前的時間
        timer.performance_timer_elapsed    = timer.performance_timer_start;
    }
}

  
 上面的代碼設置了計時器,而下面的代碼則讀出計時器并返回已經(jīng)經(jīng)過的時間,以毫秒計。代碼很簡單,首先檢查是否支持performance counter,若支持,則調用其相關函數(shù);否則調用多媒體函數(shù)。 
  

float TimerGetTime()                                // 返回經(jīng)過的時間,以毫秒為單位
{
    __int64 time;                                // 使用64位的整數(shù)

    if (timer.performance_timer)                        // 是否使用Performance Timer計時器?
    {
        QueryPerformanceCounter((LARGE_INTEGER *) &time);        // 返回當前的時間
        // 返回時間差
        return ( (float) ( time - timer.performance_timer_start) * timer.resolution)*1000.0f;
    }
    else
    {
        // 使用普通的計時器,返回時間差
        return( (float) ( timeGetTime() - timer.mm_timer_start) * timer.resolution)*1000.0f;
    }
}

  
 在下面的代碼里,我們把玩家重置在屏幕的左上角,而給敵人設置一個隨機的位置。 
  

void ResetObjects(void)                                // 重置玩家和敵人
{
    player.x=0;                                // 把玩家置于左上角
    player.y=0;                               
    player.fx=0;                               
    player.fy=0;                               

  
 接著我們給敵人一個隨機的開始位置,敵人的數(shù)量等于難度乘上當前關卡號。記著,難度最大是3,而最多有3關。因此敵人最多有9個。 
  

    for (loop1=0; loop1<(stage*level); loop1++)                // 循環(huán)隨即放置所有的敵人
    {
        enemy[loop1].x=5+rand()%6;                   
        enemy[loop1].y=rand()%11;                   
        enemy[loop1].fx=enemy[loop1].x*60;               
        enemy[loop1].fy=enemy[loop1].y*40;               
    }
}

  
 并沒有做任何改動,因此我將跳過它。在LoadGLTextures函數(shù)里我將載入那兩個紋理--背景和字體。并且我會把這兩副圖都轉化成紋理,這樣我們就可以在游戲中使用他們。紋理創(chuàng)建好之后,象素數(shù)據(jù)就可以刪除了。沒有什么新東西,你可以閱讀以前的課程以獲得更多信息。
 
  

int LoadGLTextures()                               
{
    int Status=FALSE;                           
    AUX_RGBImageRec *TextureImage[2];                   
    memset(TextureImage,0,sizeof(void *)*2);               
    if     ((TextureImage[0]=LoadBMP("Data/Font.bmp")) &&            // 載入字體紋理
         (TextureImage[1]=LoadBMP("Data/Image.bmp")))            // 載入圖像紋理
    {
        Status=TRUE;                           

        glGenTextures(2, &texture[0]);                   

        for (loop1=0; loop1<2; loop1++)                   
        {
            glBindTexture(GL_TEXTURE_2D, texture[loop1]);
            glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[loop1]->sizeX, TextureImage[loop1]->sizeY,
                0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[loop1]->data);
            glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
            glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
        }

        for (loop1=0; loop1<2; loop1++)                   
        {
            if (TextureImage[loop1])               
            {
                if (TextureImage[loop1]->data)           
                {
                    free(TextureImage[loop1]->data);   
                }
                free(TextureImage[loop1]);           
            }
        }
    }
    return Status;                           
}

  
 下面的代碼建立了顯示列表。對于字體的顯示,我已經(jīng)寫過教程。在這里我把字體圖象分成16×16個單元共256個字符。如果你有什么不明白,請參閱前面的教程 
  

GLvoid BuildFont(GLvoid)                           
{
    base=glGenLists(256);                           
    glBindTexture(GL_TEXTURE_2D, texture[0]);               
    for (loop1=0; loop1<256; loop1++)                   
    {
        float cx=float(loop1%16)/16.0f;                   
        float cy=float(loop1/16)/16.0f;                   

        glNewList(base+loop1,GL_COMPILE);               
            glBegin(GL_QUADS);                   
                glTexCoord2f(cx,1.0f-cy-0.0625f);       
                glVertex2d(0,16);               
                glTexCoord2f(cx+0.0625f,1.0f-cy-0.0625f);   
                glVertex2i(16,16);               
                glTexCoord2f(cx+0.0625f,1.0f-cy);       
                glVertex2i(16,0);               
                glTexCoord2f(cx,1.0f-cy);           
                glVertex2i(0,0);               
            glEnd();                       
            glTranslated(15,0,0);                   
        glEndList();                           
    }                                   
}

  
 當我們不再需要顯示列表的時候,銷毀它是一個好主意。在這里我仍然把代碼加上了,雖然沒有什么新東西。 
  

GLvoid KillFont(GLvoid)       
{
    glDeleteLists(base,256);                       
}

  
 函數(shù)沒有做太多改變。唯一的改動是它可以打印變量了。我把代碼列出這樣你可以容易看到改動的地方。
請注意,在這里我激活了紋理并且重置了視圖矩陣。如果set被置1的話,字體將被放大。我這樣做是希望可以在屏幕上顯示大一點的字符。在一切結束后,我會禁用紋理。 
  

GLvoid glPrint(GLint x, GLint y, int set, const char *fmt, ...)
{
    char        text[256];                       
    va_list        ap;                           

    if (fmt == NULL)       
        return;                               

    va_start(ap, fmt);                           
        vsprintf(text, fmt, ap);                       
    va_end(ap);                               

    if (set>1)                               
    {
        set=1;                           
    }
    glEnable(GL_TEXTURE_2D);                       
    glLoadIdentity();                           
    glTranslated(x,y,0);                           
    glListBase(base-32+(128*set));                       

    if (set==0)                               
    {
        glScalef(1.5f,2.0f,1.0f);                   
    }

    glCallLists(strlen(text),GL_UNSIGNED_BYTE, text);           
    glDisable(GL_TEXTURE_2D);                       
}

  
 下面的代碼基本沒有變化,只是把透視投影變?yōu)榱苏队?nbsp;
  

GLvoid ReSizeGLScene(GLsizei width, GLsizei height)                 
{
    if (height==0)                           
    {
        height=1;                           
    }

    glViewport(0,0,width,height);                       

    glMatrixMode(GL_PROJECTION);                       
    glLoadIdentity();                           

    glOrtho(0.0f,width,height,0.0f,-1.0f,1.0f);

    glMatrixMode(GL_MODELVIEW);                       
    glLoadIdentity();                           
}

  
 初始化的代碼和前面的代碼相比沒有什么改變 
  

int InitGL(GLvoid)
{
    if (!LoadGLTextures())                           
    {
        return FALSE;                           
    }

    BuildFont();                               

    glShadeModel(GL_SMOOTH);                       
    glClearColor(0.0f, 0.0f, 0.0f, 0.5f);                   
    glClearDepth(1.0f);                           
    glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);                   
    glEnable(GL_BLEND);                           
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    return TRUE;                               
}

  
 下面是我們的繪制代碼。
首先我們清空緩存,接著綁定字體的紋理,繪制游戲的提示字符串
 
  

int DrawGLScene(GLvoid)                               
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);           
    glBindTexture(GL_TEXTURE_2D, texture[0]);                // 選擇字符紋理
    glColor3f(1.0f,0.5f,1.0f);                       
    glPrint(207,24,0,"GRID CRAZY");                        // 繪制游戲名稱"GRID CRAZY"
    glColor3f(1.0f,1.0f,0.0f);                       
    glPrint(20,20,1,"Level:%2i",level2);                    // 繪制當前的級別
    glPrint(20,40,1,"Stage:%2i",stage);                    // 繪制當前級別的關卡

  
 現(xiàn)在我們檢測游戲是否結束,如果游戲結束繪制"Gmae over"并提示玩家按空格鍵重新開始 
  

    if (gameover)                                // 游戲是否結束?
    {
        glColor3ub(rand()%255,rand()%255,rand()%255);            // 隨機選擇一種顏色
        glPrint(472,20,1,"GAME OVER");                    // 繪制 GAME OVER 字符串到屏幕
        glPrint(456,40,1,"PRESS SPACE");                // 提示玩家按空格鍵重新開始
    }

  
 在屏幕的右上角繪制玩家的剩余生命 
  

    for (loop1=0; loop1<lives-1; loop1++)                    //循環(huán)繪制玩家的剩余生命
    {
        glLoadIdentity();                       
        glTranslatef(490+(loop1*40.0f),40.0f,0.0f);            // 移動到屏幕右上角
        glRotatef(-player.spin,0.0f,0.0f,1.0f);                // 旋轉繪制的生命圖標
        glColor3f(0.0f,1.0f,0.0f);                    // 繪制玩家生命
        glBegin(GL_LINES);                        // 繪制玩家圖標
            glVertex2d(-5,-5);                   
            glVertex2d( 5, 5);                   
            glVertex2d( 5,-5);                   
            glVertex2d(-5, 5);                   
        glEnd();                           
        glRotatef(-player.spin*0.5f,0.0f,0.0f,1.0f);           
        glColor3f(0.0f,0.75f,0.0f);                   
        glBegin(GL_LINES);                       
            glVertex2d(-7, 0);                   
            glVertex2d( 7, 0);                   
            glVertex2d( 0,-7);                   
            glVertex2d( 0, 7);                   
        glEnd();                           
    }

  
 下面我們來繪制網(wǎng)格,我們設置變量filled為TRUE,這告訴程序填充網(wǎng)格。
接著我們把線的寬度設置為2,并把線的顏色設置為藍色,接著我們檢測線斷是否被走過,如果走過我們設置顏色為白色。

 
  

    filled=TRUE;                                // 在測試前,把填充變量設置為TRUE
    glLineWidth(2.0f);                            // 設置線寬為2.0f
    glDisable(GL_LINE_SMOOTH);                        // 禁用反走樣
    glLoadIdentity();                           
    for (loop1=0; loop1<11; loop1++)                    // 循環(huán)11根線
    {
        for (loop2=0; loop2<11; loop2++)                // 循環(huán)每根線的線段
        {
            glColor3f(0.0f,0.5f,1.0f);                // 設置線為藍色
            if (hline[loop1][loop2])                // 是否走過?
            {
                glColor3f(1.0f,1.0f,1.0f);            // 是,設線為白色
            }
            if (loop1<10)                        // 繪制水平線
            {
                if (!hline[loop1][loop2])            // 如果當前線段沒有走過,則不填充
                {
                    filled=FALSE;               
                }
                glBegin(GL_LINES);                // 繪制當前的線段
                    glVertex2d(20+(loop1*60),70+(loop2*40));   
                    glVertex2d(80+(loop1*60),70+(loop2*40));   
                glEnd();                   
            }

  
 下面的代碼繪制垂直的線段 
  

            glColor3f(0.0f,0.5f,1.0f);                // 設置線為藍色
            if (vline[loop1][loop2])                // 是否走過
            {
                glColor3f(1.0f,1.0f,1.0f);            // 是,設線為白色
            }
            if (loop2<10)                        // 繪制垂直線
            {
                if (!vline[loop1][loop2])            // 如果當前線段沒有走過,則不填充
                {
                    filled=FALSE;               
                }
                glBegin(GL_LINES);                // 繪制當前的線段
                    glVertex2d(20+(loop1*60),70+(loop2*40));   
                    glVertex2d(20+(loop1*60),110+(loop2*40));   
                glEnd();                   
            }

  
 接下來我們檢測長方形的四個邊是否都被走過,如果被走過我們就繪制一個帶紋理的四邊形。
我們用下圖來解釋這個檢測過程




 

如果對于垂直線vline的相鄰兩個邊都被走過,并且水平線hline的相鄰兩個邊也被走過,那么我們就可以繪制這個四邊形了。我們可以使用循環(huán)檢測每一個四邊形,代碼如下: 
  

            glEnable(GL_TEXTURE_2D);                // 使用紋理映射
            glColor3f(1.0f,1.0f,1.0f);                // 設置為白色
            glBindTexture(GL_TEXTURE_2D, texture[1]);        // 綁定紋理
            if ((loop1<10) && (loop2<10))                // 繪制走過的四邊形
            {
                // 這個四邊形是否被走過?
                if (hline[loop1][loop2] && hline[loop1][loop2+1] && vline[loop1][loop2] && vline[loop1+1][loop2])
                {
                    glBegin(GL_QUADS);            // 是,則繪制它
                        glTexCoord2f(float(loop1/10.0f)+0.1f,1.0f-(float(loop2/10.0f)));
                        glVertex2d(20+(loop1*60)+59,(70+loop2*40+1));   
                        glTexCoord2f(float(loop1/10.0f),1.0f-(float(loop2/10.0f)));
                        glVertex2d(20+(loop1*60)+1,(70+loop2*40+1));   
                        glTexCoord2f(float(loop1/10.0f),1.0f-(float(loop2/10.0f)+0.1f));
                        glVertex2d(20+(loop1*60)+1,(70+loop2*40)+39);   
                        glTexCoord2f(float(loop1/10.0f)+0.1f,1.0f-(float(loop2/10.0f)+0.1f));
                        glVertex2d(20+(loop1*60)+59,(70+loop2*40)+39);   
                    glEnd();               
                }
            }
            glDisable(GL_TEXTURE_2D);               
        }
    }
    glLineWidth(1.0f);                           

  
 下面的代碼用來設置是否啟用直線反走樣 
  

    if (anti)                                // 是否啟用反走樣?
    {
        glEnable(GL_LINE_SMOOTH);                   
    }

  
 為了使游戲變得簡單些,我添加了一個時間停止器,當你吃掉它時,可以讓追擊的你的敵人停下來。
下面的代碼用來繪制一個時間停止器。
 
  

    if (hourglass.fx==1)                           
    {
        glLoadIdentity();                       
        glTranslatef(20.0f+(hourglass.x*60),70.0f+(hourglass.y*40),0.0f);   
        glRotatef(hourglass.spin,0.0f,0.0f,1.0f);           
        glColor3ub(rand()%255,rand()%255,rand()%255);           
        glBegin(GL_LINES);
            glVertex2d(-5,-5);                   
            glVertex2d( 5, 5);                   
            glVertex2d( 5,-5);                   
            glVertex2d(-5, 5);                   
            glVertex2d(-5, 5);                   
            glVertex2d( 5, 5);                   
            glVertex2d(-5,-5);                   
            glVertex2d( 5,-5);                   
        glEnd();                           
    }

  
 接下來繪制我們玩家 
  

    glLoadIdentity();
    glTranslatef(player.fx+20.0f,player.fy+70.0f,0.0f);            // 設置玩家的位置
    glRotatef(player.spin,0.0f,0.0f,1.0f);                    // 旋轉動畫
    glColor3f(0.0f,1.0f,0.0f);                       
    glBegin(GL_LINES);                           
        glVertex2d(-5,-5);                       
        glVertex2d( 5, 5);                       
        glVertex2d( 5,-5);                       
        glVertex2d(-5, 5);                       
    glEnd();                               
  
 繪制玩家的顯示效果,讓它看起來更好看些(其實沒用) 
  

    glRotatef(player.spin*0.5f,0.0f,0.0f,1.0f);
    glColor3f(0.0f,0.75f,0.0f);                       
    glBegin(GL_LINES);                           
        glVertex2d(-7, 0);                       
        glVertex2d( 7, 0);                       
        glVertex2d( 0,-7);                       
        glVertex2d( 0, 7);                       
    glEnd();                           
  
 接下來繪制追擊玩家的敵人 
  

    for (loop1=0; loop1<(stage*level); loop1++)
    {
        glLoadIdentity();                       
        glTranslatef(enemy[loop1].fx+20.0f,enemy[loop1].fy+70.0f,0.0f);
        glColor3f(1.0f,0.5f,0.5f);                   
        glBegin(GL_LINES);                       
            glVertex2d( 0,-7);                   
            glVertex2d(-7, 0);                   
            glVertex2d(-7, 0);                   
            glVertex2d( 0, 7);                   
            glVertex2d( 0, 7);                   
            glVertex2d( 7, 0);                   
            glVertex2d( 7, 0);                   
            glVertex2d( 0,-7);                   
        glEnd();                           
  
 下面的代碼繪制敵人的顯示效果,讓其更好看。 
  

        glRotatef(enemy[loop1].spin,0.0f,0.0f,1.0f);           
        glColor3f(1.0f,0.0f,0.0f);                   
        glBegin(GL_LINES);                       
            glVertex2d(-7,-7);                   
            glVertex2d( 7, 7);                   
            glVertex2d(-7, 7);                   
            glVertex2d( 7,-7);                   
        glEnd();                           
    }
    return TRUE;                               
}

  
 KillGLWindow函數(shù)基本沒有變化,只在最后一行添加KillFont函數(shù) 
  

GLvoid KillGLWindow(GLvoid)                           
{
    if (fullscreen)                           
    {
        ChangeDisplaySettings(NULL,0);                   
        ShowCursor(TRUE);                       
    }

    if (hRC)                               
    {
        if (!wglMakeCurrent(NULL,NULL))                   
        {
            MessageBox(NULL,"Release Of DC And RC Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
        }

        if (!wglDeleteContext(hRC))                   
        {
            MessageBox(NULL,"Release Rendering Context Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
        }
        hRC=NULL;                           
    }

    if (hDC && !ReleaseDC(hWnd,hDC))                   
    {
        MessageBox(NULL,"Release Device Context Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
        hDC=NULL;                           
    }

    if (hWnd && !DestroyWindow(hWnd))                   
    {
        MessageBox(NULL,"Could Not Release hWnd.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
        hWnd=NULL;                           
    }

    if (!UnregisterClass("OpenGL",hInstance))               
    {
        MessageBox(NULL,"Could Not Unregister Class.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
        hInstance=NULL;                           
    }

    KillFont();                                // 刪除創(chuàng)建的字體
}

  
 函數(shù)CreateGLWindow() and WndProc() 沒有變化。

游戲控制在WinMain中完成的
 
  

int WINAPI WinMain(    HINSTANCE    hInstance,               
            HINSTANCE    hPrevInstance,               
            LPSTR        lpCmdLine,               
            int        nCmdShow)               
{
    MSG    msg;                               
    BOOL    done=FALSE;                           

   
    if (MessageBox(NULL,"Would You Like To Run In Fullscreen Mode?", "Start FullScreen?",MB_YESNO|MB_ICONQUESTION)==IDNO)
    {
        fullscreen=FALSE;                       
    }

  
 在創(chuàng)建完OpenGL窗口后,我們添加如下的代碼,它用來創(chuàng)建玩家和敵人,并初始化時間計時器 
  

    if (!CreateGLWindow("NeHe's Line Tutorial",640,480,16,fullscreen))   
    {
        return 0;                           
    }

    ResetObjects();                                // 重置玩家和敵人
    TimerInit();                                // 初始化時間計時器

    while(!done)                               
    {
        if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))           
        {
            if (msg.message==WM_QUIT)               
            {
                done=TRUE;                   
            }
            else                           
            {
                TranslateMessage(&msg);               
                DispatchMessage(&msg);               
            }
        }
        else                               
        {

  
 接下來取得當前的時間,并在速度快的機器上讓其空循環(huán),使得程序在所有的機器上都擁有同樣的幀率 
  

            float start=TimerGetTime();                // 返回當前的時間

            if ((active && !DrawGLScene()) || keys[VK_ESCAPE])   
            {
                done=TRUE;                   
            }
            else                           
            {
                SwapBuffers(hDC);               
            }

            while(TimerGetTime()<start+float(steps[adjust]*2.0f)) {}// 速度快的機器上讓其空循環(huán)

  
 下面的部分沒有改變,按F1執(zhí)行窗口和全屏的切換 
  

            if (keys[VK_F1])
            {
                keys[VK_F1]=FALSE;               
                KillGLWindow();                   
                fullscreen=!fullscreen;               
                if (!CreateGLWindow("NeHe's Line Tutorial",640,480,16,fullscreen))
                {
                    return 0;               
                }
            }

  
 按A鍵切換是否啟用反走樣 
  

            if (keys['A'] && !ap)                    // 如果'A' 鍵被按下,啟用反走樣
            {
                ap=TRUE;                   
                anti=!anti;                   
            }
            if (!keys['A'])                       
            {
                ap=FALSE;                   
            }

  
 如果游戲沒有結束,執(zhí)行游戲循環(huán) 
  

            if (!gameover && active)                // 如果游戲沒有結束,則進行游戲循環(huán)
            {
                for (loop1=0; loop1<(stage*level); loop1++)    // 循環(huán)不同的難度等級
                {

  
 根據(jù)玩家的位置,讓敵人追擊玩家 
  

                    if ((enemy[loop1].x<player.x) && (enemy[loop1].fy==enemy[loop1].y*40))
                    {
                        enemy[loop1].x++;       
                    }

                    if ((enemy[loop1].x>player.x) && (enemy[loop1].fy==enemy[loop1].y*40))
                    {
                        enemy[loop1].x--;       
                    }

                    if ((enemy[loop1].y<player.y) && (enemy[loop1].fx==enemy[loop1].x*60))
                    {
                        enemy[loop1].y++;       
                    }

                    if ((enemy[loop1].y>player.y) && (enemy[loop1].fx==enemy[loop1].x*60))
                    {
                        enemy[loop1].y--;       
                    }

  
 如果時間停止器的顯示時間結束,而玩家又沒有吃到,那么重置計時計算器。 
  

                    if (delay>(3-level) && (hourglass.fx!=2))        // 如果沒有吃到時間停止器
                    {
                        delay=0;                    // 重置時間停止器
                        for (loop2=0; loop2<(stage*level); loop2++)    // 循環(huán)設置每個敵人的位置
                        {

  
 下面的代碼調整每個敵人的位置,并繪制它們的顯示效果 
  

                            if (enemy[loop2].fx<enemy[loop2].x*60)   
                            {
                                enemy[loop2].fx+=steps[adjust];   
                                enemy[loop2].spin+=steps[adjust];   
                            }
                            if (enemy[loop2].fx>enemy[loop2].x*60)   
                            {
                                enemy[loop2].fx-=steps[adjust];   
                                enemy[loop2].spin-=steps[adjust];   
                            }
                            if (enemy[loop2].fy<enemy[loop2].y*40)   
                            {
                                enemy[loop2].fy+=steps[adjust];   
                                enemy[loop2].spin+=steps[adjust];   
                            }
                            if (enemy[loop2].fy>enemy[loop2].y*40)   
                            {
                                enemy[loop2].fy-=steps[adjust];   
                                enemy[loop2].spin-=steps[adjust];   
                            }
                        }
                    }

  
 如果敵人的位置和玩家的位置相遇,這玩家死亡,開始新的一局 
  

                    // 敵人的位置和玩家的位置相遇?
                    if ((enemy[loop1].fx==player.fx) && (enemy[loop1].fy==player.fy))
                    {
                        lives--;            // 如果是,生命值減1

                        if (lives==0)            // 如果生命值為0,則游戲結束
                        {
                            gameover=TRUE;       
                        }

                        ResetObjects();            // 重置所有的游戲變量
                        PlaySound("Data/Die.wav", NULL, SND_SYNC);    // 播放死亡的音樂
                    }
                }

  
 使用上,下,左,右控制玩家的位置 
  

                if (keys[VK_RIGHT] && (player.x<10) && (player.fx==player.x*60) && (player.fy==player.y*40))
                {
                    hline[player.x][player.y]=TRUE;       
                    player.x++;               
                }
                if (keys[VK_LEFT] && (player.x>0) && (player.fx==player.x*60) && (player.fy==player.y*40))
                {
                    player.x--;               
                    hline[player.x][player.y]=TRUE;       
                }
                if (keys[VK_DOWN] && (player.y<10) && (player.fx==player.x*60) && (player.fy==player.y*40))
                {
                    vline[player.x][player.y]=TRUE;       
                    player.y++;               
                }
                if (keys[VK_UP] && (player.y>0) && (player.fx==player.x*60) && (player.fy==player.y*40))
                {
                    player.y--;               
                    vline[player.x][player.y]=TRUE;       
                }

  
 調整玩家的位置,讓動畫看起來跟自然 
  

                if (player.fx<player.x*60)           
                {
                    player.fx+=steps[adjust];       
                }
                if (player.fx>player.x*60)           
                {
                    player.fx-=steps[adjust];       
                }
                if (player.fy<player.y*40)           
                {
                    player.fy+=steps[adjust];       
                }
                if (player.fy>player.y*40)           
                {
                    player.fy-=steps[adjust];       
                }
            }

  
 如果游戲結束,按空格開始新的一局游戲 
  

            else                            // 如果游戲結束
            {
                if (keys[' '])                    // 按下空格?
                {
                    gameover=FALSE;                // 開始新的一局
                    filled=TRUE;                // 重置所有的變量
                    level=1;               
                    level2=1;           
                    stage=0;               
                    lives=5;               
                }
            }

  
 如果順利通過本關,播放通關音樂,并提高游戲難度,開始新的一局 
  

            if (filled)                        // 所有網(wǎng)格是否填滿
            {
                PlaySound("Data/Complete.wav", NULL, SND_SYNC);    // 播放過關音樂
                stage++;                    // 增加游戲難度
                if (stage>3)                    // 如果當前的關卡大于3,則進入到下一個大的關卡?
                {
                    stage=1;                // 重置當前的關卡
                    level++;                // 增加大關卡的值
                    level2++;               
                    if (level>3)               
                    {
                        level=3;            // 如果大關卡大于3,則不再增加
                        lives++;            // 完成一局給玩家獎勵一條生命
                        if (lives>5)            // 如果玩家有5條生命,則不再增加
                        {
                            lives=5;       
                        }
                    }
                }

  
 進入到下一關卡,重置所有的游戲變量 
  

                ResetObjects();                   

                for (loop1=0; loop1<11; loop1++)
                {
                    for (loop2=0; loop2<11; loop2++)   
                    {
                        if (loop1<10)           
                        {
                            hline[loop1][loop2]=FALSE;   
                        }
                        if (loop2<10)           
                        {
                            vline[loop1][loop2]=FALSE;   
                        }
                    }
                }
            }

  
 如果玩家吃到時間停止器,記錄這一信息 
  

            if ((player.fx==hourglass.x*60) && (player.fy==hourglass.y*40) && (hourglass.fx==1))
            {
                // 播放一段聲音
                PlaySound("Data/freeze.wav", NULL, SND_ASYNC | SND_LOOP);
                hourglass.fx=2;                    // 設置fx為2,表示吃到時間停止器
                hourglass.fy=0;                    // 設置fy為0
            }

  
 顯示玩家的動畫效果 
  

            player.spin+=0.5f*steps[adjust];            // 旋轉動畫
            if (player.spin>360.0f)                   
            {
                player.spin-=360;               
            }

  
 顯示時間停止器的動畫 
  

            hourglass.spin-=0.25f*steps[adjust];            // 旋轉動畫
            if (hourglass.spin<0.0f)               
            {
                hourglass.spin+=360.0f;               
            }

  
 下面的代碼計算何時出現(xiàn)一個時間停止計數(shù)器 
  

            hourglass.fy+=steps[adjust];                // 增加fy的值,當他大于一定的時候,產生時間停止計數(shù)器
            if ((hourglass.fx==0) && (hourglass.fy>6000/level))   
            {                           
                PlaySound("Data/hourglass.wav", NULL, SND_ASYNC);   
                hourglass.x=rand()%10+1;           
                hourglass.y=rand()%11;               
                hourglass.fx=1;                    //fx=1表示時間停止器出現(xiàn)                   
                hourglass.fy=0;                   
            }

  
 如果玩家沒有拾取時間停止器,則過一段時間后,它自動消失 
  

            if ((hourglass.fx==1) && (hourglass.fy>6000/level))   
            {               
                hourglass.fx=0;                    // 消失后重置時間停止器
                hourglass.fy=0;                   
            }

  
 如果玩家吃到時間停止器,在時間停止停止階段播放一段音樂,過一段時間停止播放音樂 
  

            if ((hourglass.fx==2) && (hourglass.fy>500+(500*level)))
            {                           
                PlaySound(NULL, NULL, 0);            // 停止播放音樂
                hourglass.fx=0;                    // 重置變量
                hourglass.fy=0;                   
            }

  
 增加敵人的延遲計數(shù)器的值,這個值用來更新敵人的運動
 
  

            delay++;                        // 增加敵人的延遲計數(shù)器的值
        }
    }

    // 關閉
    KillGLWindow();                                // 刪除窗口
    return (msg.wParam);                            // 退出程序
}

  
 我花了很長時間寫這份教程,它開始于一個簡單的直線教程,結束與一個小型的游戲。希望它能給你一些有用的信息,我知道你們中大部分喜歡那些基于“貼圖”的游戲,但我覺得這些將教會你關于游戲更多的東西。如果你不同意我的看法,請讓我知道,因為我想寫最好的OpenGL教程。
請注意,這是一個很大的程序了。我盡量去注釋每一行代碼,我知道程序運行的一切細節(jié),但把它表達出來又是另一回事。如果你有更好的表達能力,請告訴我如何更好的表達。我希望通過我們的努力,這份教程越來越好。謝謝

 


posted on 2007-12-17 16:53 sdfasdf 閱讀(1192) 評論(0)  編輯 收藏 引用 所屬分類: OPENGL
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            亚洲精选中文字幕| 国产精品久久久亚洲一区 | 欧美国产欧美亚洲国产日韩mv天天看完整| 国产欧美日韩视频| 国产精品高潮粉嫩av| 欧美区亚洲区| 欧美日韩三区| 久久久久国色av免费观看性色| 亚洲一区二区三区色| 在线视频欧美日韩| 亚洲国产精品第一区二区三区| 久久免费精品日本久久中文字幕| 久久精品在线播放| 欧美国产精品| 午夜精品美女久久久久av福利| 久久久精品日韩| 欧美日韩视频一区二区| 国产日韩专区| 亚洲乱码国产乱码精品精天堂| 亚洲视频国产视频| 欧美在线91| 亚洲福利视频一区二区| 亚洲免费影视| 欧美精品久久久久a| 国产亚洲欧洲| 亚洲色图在线视频| 免费影视亚洲| 亚洲欧美日本精品| 欧美精品一区三区在线观看| 国产在线高清精品| 中文精品99久久国产香蕉| 久久久久www| 99精品免费| 欧美ed2k| 一区免费观看| 欧美一级视频免费在线观看| 亚洲国产毛片完整版| 欧美在线你懂的| 国产精品久久久久久久久免费樱桃 | 欧美精品一区二区三区很污很色的| 国产精品久久久久久影视| 亚洲精品久久久久久久久久久久久 | 国产一区二区三区无遮挡| 亚洲午夜精品久久久久久app| 欧美国产亚洲视频| 久久久人成影片一区二区三区| 国产精品久久久久国产a级| 一区二区免费在线视频| 免费看的黄色欧美网站| 久久成人免费电影| 国产精品日韩精品| 亚洲欧美中文字幕| 亚洲视频福利| 国产精品家教| 欧美一二三视频| 亚洲欧洲99久久| 国产日韩欧美高清免费| 欧美在线视频在线播放完整版免费观看| 99精品国产在热久久婷婷| 欧美视频亚洲视频| 亚洲一区网站| 午夜伦欧美伦电影理论片| 国产午夜久久久久| 久久久久这里只有精品| 久久激情一区| 亚洲黄色毛片| 亚洲精品久久久久久久久久久| 欧美成人亚洲成人| 这里只有视频精品| 亚洲免费在线观看视频| 国产精品自在欧美一区| 久久欧美中文字幕| 蜜桃精品久久久久久久免费影院| 亚洲欧洲美洲综合色网| 亚洲精品视频在线| 国产精品免费在线| 裸体一区二区三区| 欧美日韩国产综合久久| 午夜精品免费视频| 欧美综合激情网| 亚洲国内高清视频| 一区二区黄色| 影音先锋亚洲一区| 日韩一二在线观看| 国产日韩欧美视频在线| 欧美www视频| 欧美亚州韩日在线看免费版国语版| 午夜视频在线观看一区二区| 久久久久九九九| 亚洲性感美女99在线| 亚洲欧美另类在线| 极品少妇一区二区| 亚洲天堂av图片| 在线欧美福利| 亚洲视频专区在线| 亚洲国产精品久久| 亚洲一区二三| 99精品国产热久久91蜜凸| 午夜在线观看免费一区| 久久精品人人爽| 亚洲一区在线直播| 欧美成人激情在线| 久久久久久久综合色一本| 欧美日本国产精品| 免费欧美高清视频| 国产视频在线一区二区| 亚洲乱码国产乱码精品精天堂 | 国产精品久久久久久妇女6080| 免费视频久久| 国产欧美日韩精品在线| 一本一本久久a久久精品综合麻豆 一本一本久久a久久精品牛牛影视 | 卡通动漫国产精品| 欧美一级久久久久久久大片| 欧美日韩一级大片网址| 欧美成人一区二区三区片免费| 国产精品福利av| 亚洲精品国产视频| 亚洲日本久久| 麻豆freexxxx性91精品| 久久久噜噜噜久久久| 国产精品久久久久影院亚瑟| 亚洲黑丝一区二区| 亚洲国产天堂久久综合| 久久午夜电影网| 狂野欧美一区| 精品96久久久久久中文字幕无| 亚洲欧美一区二区视频| 亚洲欧美日韩第一区| 国产精品av一区二区| 在线亚洲观看| 欧美一区二区三区免费观看视频 | 欧美在线播放高清精品| 国产精品剧情在线亚洲| 亚洲最快最全在线视频| 亚洲视频观看| 国产精品免费观看在线| 亚洲免费视频一区二区| 欧美在线一二三区| 国产在线观看精品一区二区三区| 午夜精品影院| 久久久久久精| 亚洲第一精品福利| 欧美成人一区二免费视频软件| 亚洲国产日韩欧美在线99| 一本到12不卡视频在线dvd| 欧美日韩国产成人高清视频| 99v久久综合狠狠综合久久| 亚洲视频视频在线| 国产精品美女久久久久久2018| 亚洲综合电影| 久久综合影音| 日韩一级裸体免费视频| 欧美三区视频| 久久精品人人做人人综合 | 久久国产精品99精品国产| 久久婷婷久久| 亚洲三级免费| 国产精品欧美久久久久无广告| 亚洲一区免费网站| 嫩草国产精品入口| 亚洲少妇在线| 国产午夜亚洲精品羞羞网站| 久久夜色精品| 在线亚洲一区| 免费看黄裸体一级大秀欧美| 亚洲少妇最新在线视频| 国产精品综合视频| 蜜臀av性久久久久蜜臀aⅴ| 亚洲美女少妇无套啪啪呻吟| 性欧美1819性猛交| 亚洲国产婷婷香蕉久久久久久99| 欧美日韩精品久久久| 欧美在线你懂的| 欧美激情成人在线视频| 欧美一级艳片视频免费观看| 亚洲肉体裸体xxxx137| 国产日韩欧美综合| 欧美人与禽猛交乱配| 午夜精品福利电影| 最新精品在线| 老色鬼久久亚洲一区二区| 亚洲午夜国产成人av电影男同| 国内免费精品永久在线视频| 欧美日韩国产精品专区| 久久亚洲高清| 欧美一级二级三级蜜桃| 亚洲毛片av在线| 亚洲高清视频的网址| 久久婷婷国产麻豆91天堂| 午夜日韩视频| 亚洲天堂av电影| 亚洲免费观看高清完整版在线观看| 国产一区高清视频| 国产日韩欧美不卡在线| 国产精品久久午夜夜伦鲁鲁| 欧美日韩国产在线一区| 欧美激情综合色综合啪啪| 免费观看成人鲁鲁鲁鲁鲁视频| 久久精品国产亚洲一区二区三区| 亚洲欧美日韩另类精品一区二区三区|