OpenGL實現三維迷宮遊戲(一)

《計算機圖形學》這門課的第二個實驗,覺得還挺有意思的…

實驗要求

設計一個OpenGL程序,創建一個三維迷宮,支持替身通過一定交互手段在迷宮中漫遊,基本功能包括:
- 迷宮應當至少包含10 * 10 個Cell,不能過於簡單,下圖給出一種示例。
- 讀取給定的替身模型,加載到場景中。
- 鍵盤方向鍵控制替身轉向與漫遊。
- 有碰撞檢測,替身不應當穿牆。
- 支持切換第一視角和第三視角進行觀察。
- 迷宮場景中的牆、地面等應貼上紋理。
附加要求(可選擇一個):
- 同時加入二維輔助地圖,替身在三維迷宮探索的同時,在小地圖中顯示已經探索的區域;(我選的是這一個,其他的由於最近事情比較多就沒有做,以後有機會再補吧…如果有機會的話…=。=)
- 在俯視狀態下,可以通過鼠標點選替身需要到達的目的地,通過尋徑算法,控制替身自動到達目的地;
- 迷宮地圖交互編輯功能,例如,可以設計一個二維地圖編輯器,根據用戶的繪製,拉伸得到三維迷宮場景;
- 其他相當難度,可以增加迷宮遊戲趣味性的功能(需要通過指導老師認可)

實現過程

投影模式採用透視投影,第一、三視角之間的切換隻需改變gluLookAt(GLdouble eyex,GLdouble eyey,GLdouble eyez,GLdouble centerx,GLdouble centery,GLdouble centerz,GLdouble upx,GLdouble upy,GLdouble upz);的參數值即可。

main()方法:

int main(int argc,char **argv){
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGB|GLUT_DOUBLE|GLUT_DEPTH);

    glutInitWindowPosition(300, 50);
    glutInitWindowSize(700, 700);
    glutCreateWindow("迷宮");

    init();

    glutDisplayFunc(display);
    glutMainLoop();

    return 0;
}

init()方法:

void init(){

    glClearColor(0.8, 0.8, 0.8, 1);//用灰色清屏
    glEnable(GL_DEPTH_TEST);//開啓深度測試
    glEnable(GL_TEXTURE_2D);//啓用二維紋理
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(50, 1, 0.5, 100);/*其實一開始ZNear設的是1~*/
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    gluLookAt(lookX, lookY, lookZ, centerX,centerY,centerZ,upX,upY,upZ);

    glShadeModel(GL_SMOOTH);     //使用平滑明暗處理  
    glEnable(GL_DEPTH_TEST);     //剔除隱藏面  
    glEnable(GL_CULL_FACE);      //不計算多邊形背面  
    glFrontFace(GL_CCW);      //多邊形逆時針方向爲正面

{
        //三視圖光源
        GLfloat light0_position[] = {10.0f, 10.0f, 0.0f, 1.0f };
        GLfloat light0_ambient[] = { 0.8f, 0.8f, 0.8f, 1.0f };
        GLfloat light0_diffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f };

        glLightfv(GL_LIGHT0, GL_POSITION, light0_position);
        glLightfv(GL_LIGHT0, GL_AMBIENT, light0_ambient);
        glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_diffuse);

        //一視圖光源
        GLfloat light1_position[] = { 10.0f, 10.0f, 0.0f, 1.0f };
        GLfloat light1_ambient[] = { 0.0f, 0.0f, 0.0f, 1.0f };
        GLfloat light1_diffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f };
        GLfloat light1_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f };

        glLightfv(GL_LIGHT1, GL_POSITION, light1_position);
        glEnable(GL_LIGHTING);//開啓光照明
        glEnable(GL_DEPTH_TEST);
}

參數的初始值:

double lookX=0, lookY=0, lookZ=15;//相機在世界座標的位置
double centerX = 0, centerY = 0, centerZ = 0;//相機鏡頭對準的物體在世界座標的位置
double upX = 0, upY = 1, upZ = 0;//相機向上的方向在世界座標中的方向

關於gluPerspective()的理解推薦看OpenGL函數思考-gluPerspectivegluLookAt()挺好理解的就不推薦了。

display()方法:

void display(){

    drawMaze();//畫迷宮
    glutSwapBuffers();/*這句很重要!!!剛開始學OpenGL的時候沒注意這個,結果畫出來什麼都沒有是全白的。開了雙緩衝就要寫。*/

}

迷宮我是用對應位置及數量的小立方體拼起來的,所以先聲明瞭一個方法drawCube(double x, double y, double z)專門用於繪製立方體。

void drawCube(double x, double y, double z){


    glPushMatrix();/*!劃重點!不寫後果很嚴重(當然這個錯誤不是我犯得哈哈)*/
    glTranslatef(x, y, z);
    glColor3f(1.0f, 1.0f, 1.0f);
    glBegin(GL_QUADS);   
    glNormal3f(0.0f, 1.0f, 0.0f);//法向量,光照明要用的
    glVertex3f(0.5f, 0.5f, 0.5f);
    glVertex3f(0.5f, 0.5f, -0.5f);
    glVertex3f(-0.5f, 0.5f, -0.5f);
    glVertex3f(-0.5f, 0.5f, 0.5f);
    glEnd();
    glBegin(GL_QUADS);      
    glNormal3f(0.0f, -1.0f, 0.0f);
    glVertex3f(0.5f, -0.5f, 0.5f);
    glVertex3f(-0.5f, -0.5f, 0.5f);
    glVertex3f(-0.5f, -0.5f, -0.5f);
    glVertex3f(0.5f, -0.5f, -0.5f);
    glEnd();
    glBegin(GL_QUADS);    
    glNormal3f(0.0f, 0.0f, 1.0f);
    glVertex3f(0.5f, 0.5f, 0.5f);
    glVertex3f(-0.5f, 0.5f, 0.5f);
    glVertex3f(-0.5f, -0.5f, 0.5f);
    glVertex3f(0.5f, -0.5f, 0.5f);
    glEnd();
    glBegin(GL_QUADS);    
    glNormal3f(0.0f, 0.0f, -1.0f);
    glVertex3f(0.5f, 0.5f, -0.5f);
    glVertex3f(0.5f, -0.5f, -0.5f);
    glVertex3f(-0.5f, -0.5f, -0.5f);
    glVertex3f(-0.5f, 0.5f, -0.5f);
    glEnd();
    glBegin(GL_QUADS);   
    glNormal3f(-1.0f, 0.0f, 0.0f);
    glVertex3f(-0.5f, 0.5f, 0.5f);
    glVertex3f(-0.5f, 0.5f, -0.5f);
    glVertex3f(-0.5f, -0.5f, -0.5f);
    glVertex3f(-0.5f, -0.5f, 0.5f);
    glEnd();
    glBegin(GL_QUADS);   
    glNormal3f(1.0f, 0.0f, 0.0f);
    glVertex3f(0.5f, 0.5f, 0.5f);
    glVertex3f(0.5f, -0.5f, 0.5f);
    glVertex3f(0.5f, -0.5f, -0.5f);
    glVertex3f(0.5f, 0.5f, -0.5f);
    glEnd();
    glPopMatrix();/*有Push當然要有Pop*/
}

畫迷宮我是用數組存的,因爲還要實現同時加入二維輔助地圖,替身在三維迷宮探索的同時,在小地圖中顯示已經探索的區域這個功能。(感覺很弱雞啊…但是也沒想出其他好辦法…好在跑起來不卡…哈…哈…)
聲明數組int maze[900]用於存儲一個30x30的迷宮。用0和1初始化數組。

  • maze[i]=0: 座標(i - i / 30 * 30, i / 30,-20)處不繪製立方體。
  • maze[j]=1: 座標(j - j / 30 * 30, j / 30,-20)處繪製立方體。

(初始化數組的過程趕時間寫的超爛…不放了就…)

void drawMaze(){
    glEnable(GL_SCISSOR_TEST);
    glScissor(0, 0, 700, 700);

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glDisable(GL_SCISSOR_TEST);

    glViewport(0, 0,700,700);

    glEnable(GL_LIGHT0);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(50, 1, 0.5, 100);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    gluLookAt(lookX, lookY, lookZ, centerX, centerY, centerZ, upX, upY, upZ);

    //drawGamer();
    //畫三維地圖
    glPushMatrix();
    glTranslatef(-15, -14, 0);
    for (int i = 0; i < 900; i++){
        if (maze[i] == 1||maze[i]==-1){

            drawCube(i - i / 30 * 30, i / 30,-20);
        }

    }
    glPopMatrix();
    //畫地板

    glPushMatrix();
    glColor3f(1.0f, 1.0f, 1.0f);
    glBegin(GL_QUADS);
    glNormal3f(0.0f, 0.0f, 1.0f);
    glVertex3f(14, 15, -20.5);
    glVertex3f(-15, 15, -20.5);
    glVertex3f(-15, -14.9, -20.5);
    glVertex3f(14, -14.9, -20.5);
    glEnd();
    glPopMatrix();
}

效果應該就是這樣orz有點醜…貼上紋理會好很多的…
這裏寫圖片描述

有空再接着寫實現了全部功能的:)
完整源代碼下載

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章