Boss说,要看OpenGL,看了快一个月,总算出了个像样的东西,用C写了个3D迷宫, 虽然只有350行
代码,不过边学边写,足足写了一周时间,还是小有成就感的,活活活!
Tips:上下左右键控制前进后退转向,空格键切换俯视图,鼠标右键更换地图(虽然只写了两
个……) 加了点音乐,免得太过单调。
效果图:
#include<stdlib.h>
#include<stdio.h>
#include<GL/glut.h>
#include<GL/glaux.h>
#include<math.h>
#include<windows.h>
#pragma comment(lib, "glaux.lib")
#define PX_START 1.5
#define PY_START 1.5
#define UNITSTEP 0.2
#define ANGLE_START -45
GLuint Texture = 0 ;
float px = PX_START ;
float py = PY_START ;
int angle = ANGLE_START ; //行走方向
int dir_x ; //行走方向向量
int dir_y ;
int MAP_SIZE = 16 ;
char **map ;
int globalView = 0 ; //是否查看俯视图
char *map1[16] =
{
"HHHHHHHHHHHHHHHH",
"H H H",
"H H HHH H H H",
"H HH H HH H H H",
"H H H H",
"HHHHHHHHHH HHH H",
"H H H",
"H HHHHH HHH HHHH",
"H H H H H",
"H HHHHHHH H",
"H H H H H H",
"H HHHHH HHHH H H",
"H H H H",
"HH HH HHHH HHH H",
"H H H H H",
"HHHHHHHHHHHHH HH"
};
char *map2[25] =
{
"HHHHHHHHHHHHHHHHHHHHHHHHH",
"H H H H HH H H",
"H HH H H H HHH HH H",
"H H HH H HHH HHH",
"H H HHH HH H HH H HHHHH",
"H HH HHHH HH H H HH HHH",
"H H H HH HH HH",
"H HH HHH H HH HH HH HH",
"H H HHH H HH HH H",
"HH H H H H HH H HH HH",
"HHH H HH HH H HHH H",
"HHH HHH H H H HH HHH H",
"HHH HHH H HH HH HH H",
"HHH H HHHH H H H H H",
"HH HHH HH H H HHH H",
"HHHH HHHHH HHH HH HH H",
"HHH H HHHHH HHHH HH HH",
"HHH HH HH HHH HH H",
"HHH HHH HHH HH HHH HH H",
"HHH HH HHHH HHH HH HHH",
"HHH H HH HHHH HHH HHH",
"H H HHH HH H H HHH",
"H HH HH HH HHH",
"H HH HHHH HHHHH H HH",
"HHHHHHHHHHHHHHHHHHHHHH HH"
};
// 加载墙纸
int ReadImage()
{
AUX_RGBImageRec *TextureImage; //保存贴图数据的指针
TextureImage = auxDIBImageLoad("wall.bmp"); //载入贴图数据
glGenTextures(1, &Texture); // 创建一个纹理,unTexture
glBindTexture(GL_TEXTURE_2D, Texture); //绑定纹理,然后对该纹理区添加纹理数据
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, TextureImage->sizeX, TextureImage->sizeY,GL_RGB, GL_UNSIGNED_BYTE, TextureImage->data);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); //设置滤波为线性滤波
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); //线性滤波
glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_DECAL) ;
if (TextureImage) //释放资源
{
if (TextureImage->data)
{
free(TextureImage->data);
}
free(TextureImage);
}
return 1;
}
// 判断是否为墙
int wall(int x , int y)
{
if(map[(int)x][(int)y]=='H')
return 1 ;
return 0 ;
}
// 计算行走方向向量
void calcDir()
{
if(angle<0 && angle>-180) dir_x = 1 ;
else if(angle<180 && angle>0) dir_x = -1 ;
else dir_x = 0 ;
if(abs(angle) < 90) dir_y = 1 ;
else if(abs(angle) > 90) dir_y = -1 ;
else dir_y = 0 ;
}
// 绘制迷宫墙体
int drawCube(int x , int y)
{
glBindTexture(GL_TEXTURE_2D, Texture); //使用贴图纹理
glPushMatrix(); //压入变换矩阵
glTranslatef((float)x+0.5,(float)y+0.5,0.0f) ;
glBegin(GL_QUADS); //启用四边形带绘制模式绘制
//前面
glTexCoord2f(0.0f, 0.0f); glVertex3f(-0.5f, -0.5f, 0.5f);
glTexCoord2f(1.0f, 0.0f); glVertex3f( 0.5f, -0.5f, 0.5f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 0.5f, 0.5f, 0.5f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-0.5f, 0.5f, 0.5f);
//后面
glTexCoord2f(0.0f, 0.0f); glVertex3f( 0.5f, -0.5f, -0.5f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-0.5f, -0.5f, -0.5f);
glTexCoord2f(1.0f, 1.0f); glVertex3f(-0.5f, 0.5f, -0.5f);
glTexCoord2f(0.0f, 1.0f); glVertex3f( 0.5f, 0.5f, -0.5f);
//上面
glTexCoord2f(0.0f, 0.0f); glVertex3f(-0.5f, 0.5f, 0.5f);
glTexCoord2f(1.0f, 0.0f); glVertex3f( 0.5f, 0.5f, 0.5f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 0.5f, 0.5f, -0.5f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-0.5f, 0.5f, -0.5f);
//下面
glTexCoord2f(0.0f, 0.0f); glVertex3f(-0.5f, -0.5f, -0.5f);
glTexCoord2f(1.0f, 0.0f); glVertex3f( 0.5f, -0.5f, -0.5f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 0.5f, -0.5f, 0.5f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-0.5f, -0.5f, 0.5f);
//右面
glTexCoord2f(0.0f, 0.0f); glVertex3f( 0.5f, -0.5f, 0.5f);
glTexCoord2f(0.0f, 1.0f); glVertex3f( 0.5f, -0.5f, -0.5f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 0.5f, 0.5f, -0.5f);
glTexCoord2f(1.0f, 0.0f); glVertex3f( 0.5f, 0.5f, 0.5f);
//左面
glTexCoord2f(0.0f, 0.0f); glVertex3f(-0.5f, -0.5f, -0.5f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-0.5f, -0.5f, 0.5f);
glTexCoord2f(1.0f, 1.0f); glVertex3f(-0.5f, 0.5f, 0.5f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-0.5f, 0.5f, -0.5f);
glEnd();
glPopMatrix(); //弹出变换矩阵
return 1;
}
// 绘制迷宫地板
int drawFloor(int x , int y)
{
glPushMatrix(); //压入变换矩阵
glDisable(GL_TEXTURE_2D) ;
glColor3f(0.7,0.7,0.7) ;
glTranslatef((float)x+0.5,(float)y+0.5,0.0f) ;
glBegin(GL_QUADS); //启用四边形带绘制模式绘制
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();
glEnable(GL_TEXTURE_2D) ;
glPopMatrix() ;
return 1 ;
}
// 标明当前位置和方向
int drawPlayer()
{
glPushMatrix() ;
glDisable(GL_TEXTURE_2D) ;
glColor3f(0.2,0.8,0.2) ;
glTranslatef(px,py,0.0f) ;
glRotatef(angle,0.0,0.0,1.0) ;
glBegin(GL_QUADS); //启用四边形带绘制模式绘制
glVertex3f(-0.2f, -0.4f, 1.0f) ;
glVertex3f( 0.2f, -0.4f, 1.0f) ;
glVertex3f( 0.0f, 0.0f, 1.0f) ;
glVertex3f( 0.0f, 0.4f, 1.0f) ;
glEnd();
glEnable(GL_TEXTURE_2D) ;
glPopMatrix() ;
return 1 ;
}
// 绘制迷宫
void drawMap()
{
int x , y ;
for( x = 0 ; x < MAP_SIZE ; x++ )
for( y = 0 ; y < MAP_SIZE ; y++)
if(map[x][y] == 'H')
drawCube(x,y) ;
else
drawFloor(x,y) ;
drawPlayer() ;
}
// 初始化绘制环境
void init()
{
glEnable(GL_CULL_FACE); //启用裁剪
glCullFace(GL_BACK); //背面裁剪(背面不可见)
glShadeModel(GL_FLAT) ;
glEnable(GL_AUTO_NORMAL) ;
glEnable(GL_TEXTURE_2D);
ReadImage() ;
calcDir() ;
map = map1 ;
MAP_SIZE = 16 ;
PlaySound("BACK.wav",NULL,SND_ASYNC|SND_LOOP);
}
// 绘制函数
void display(void)
{
glClearColor(1.0,1.0,1.0,1.0) ;
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT) ; // 清空颜色数据和深度数据
if(px>(MAP_SIZE-1) && px<MAP_SIZE && py>(MAP_SIZE-3) && py<(MAP_SIZE-2))
{
PlaySound("YEAH.wav",NULL,SND_ASYNC);
MessageBox(NULL , "Escaped ! " , "Message" , MB_ICONASTERISK);
PlaySound("BACK.wav",NULL,SND_ASYNC|SND_LOOP);
px = PX_START ;
py = PY_START ;
angle = ANGLE_START ;
calcDir() ;
}
glMatrixMode(GL_MODELVIEW) ;
glLoadIdentity() ;
drawMap() ;
glMatrixMode(GL_PROJECTION) ;
glLoadIdentity() ;
glEnable(GL_DEPTH_TEST) ;
gluPerspective(90,1.0,0.01,16.0) ;
if(globalView == 0)
gluLookAt(px,py,0.0f,px+dir_x,py+dir_y,0.0f,0.0f,0.0f,1.0f) ;
else
gluLookAt(px,py,7.0f,px,py,0.0f,0.0f,1.0f,0.0) ;
glutSwapBuffers();
}
// 地图选择
void MenuFunc(int data)
{
switch(data)
{
case 1: map = map1 ; MAP_SIZE = 16 ; break ;
case 2: map = map2 ; MAP_SIZE = 25 ; break ;
case 3: map = map2 ; MAP_SIZE = 25 ; break ;
default : break ;
}
angle = ANGLE_START ;
px = PX_START ;
py = PY_START ;
calcDir() ;
}
// 控制移动
void aheadAndBack(float pos)
{
float step_x = pos * UNITSTEP * dir_x ;
float step_y = pos * UNITSTEP * dir_y ;
if(wall(px+step_x , py) == 0)
px += step_x ;
if(wall(px , py+step_y) == 0)
py += step_y ;
}
// 键盘事件
void keyboard(unsigned char key, int x, int y)
{
if(key==' ')
globalView = (globalView + 1) % 2 ;
}
// 键盘事件
void special(int key , int x , int y)
{
if(globalView == 0) //俯视图屏蔽方向控制
switch(key)
{
case GLUT_KEY_UP : aheadAndBack(1.0) ; break ;
case GLUT_KEY_DOWN : aheadAndBack(-1.0) ; break ; //向后走相当于向前走-1
case GLUT_KEY_LEFT : angle += 45 ; if(angle > 180) angle = -135 ; calcDir() ; break ;
case GLUT_KEY_RIGHT :angle -= 45 ; if(angle < -180) angle = 135 ; calcDir() ; break ;
default : break ;
}
}
// 空闲时调用
void idle(void)
{
Sleep(10) ;
glutPostRedisplay() ;
}
// 窗口调整
void reshape(GLsizei w , GLsizei h)
{
glViewport(0,0,w,h) ;
glMatrixMode(GL_PROJECTION) ;
glLoadIdentity() ;
glMatrixMode(GL_MODELVIEW) ;
glLoadIdentity() ;
}
// 主函数
int main(int argc , char** argv)
{
glutInit(&argc,argv) ;
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB) ;
glutInitWindowSize(800,800) ;
glutInitWindowPosition(150,150) ;
glutCreateWindow("Maze") ;
init() ;
glutReshapeFunc(reshape) ;
glutDisplayFunc(display) ;
glutSpecialFunc(special) ;
glutKeyboardFunc(keyboard) ;
glutIdleFunc(idle);
glutCreateMenu(MenuFunc);
glutAddMenuEntry("Ordinary",1);
glutAddMenuEntry("Medium",2);
glutAddMenuEntry("Maddening",3);
glutAttachMenu(GLUT_RIGHT_BUTTON);
glutMainLoop() ;
return(0) ;
}