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有点丑…贴上纹理会好很多的…
这里写图片描述

有空再接着写实现了全部功能的:)
完整源代码下载

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