利用C++与OpenGL实现贪吃蛇游戏

这个小游戏截取自本人的计算机图形学课程设计,其中有一个关于二维场景的绘制任务,我把主要精力放在了制作这个贪吃蛇小游戏上,但由于该程序还有其他内容的显示,整体代码量较大,所以这里就只展示贪吃蛇游戏的实现原理。

完整代码见以下链接,包含二维和三维场景的完整绘制:

中国地质大学(武汉)计算机图形学课程设计-C++文档类资源-CSDN文库https://download.csdn.net/download/qq_58010729/85418717?spm=1001.2014.3001.5503

程序运行后,右键鼠标,选择“snake”可以开启贪吃蛇游戏。在原先的坐标系体系下会出现一条模拟的贪吃蛇,而且会在随机的某个地方产生一个黑色方块,代表“食物”: 

利用C++与OpenGL实现贪吃蛇游戏_第1张图片 贪吃蛇游戏初始界面

按下P键可以开始游戏,这时贪吃蛇就会自己开始移动,再次按P键则会暂停。通过方向键(这里是W—上,S—下,A—左,D—右)可以控制移动方向;每当头部触碰到食物时,贪吃蛇长度就会增加:

利用C++与OpenGL实现贪吃蛇游戏_第2张图片 随着食物的摄取,贪吃蛇长度变长

 如果撞到了边界,则游戏会结束。这时控制台上会显示得分,该得分的含义即为吃到了几个食物:

控制台显示最终得分

程序部分,在graphics函数的DrawScene场景下有sanke的判断接口:

1.	if (snake) {  
2.	    clear = false;  
3.	    snakestart();  
4.	}  

进入snakestart后,会有一些的新的窗口设置和回调函数:

1.	void snakestart() {    
2.	        glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);    
3.	        glutDisplayFunc(display);  
4.	        glutKeyboardFunc(keyboard);  
5.	        glutTimerFunc(100, TimerFunc, 0);  
6.	        initializeGame();  
7.	} 

例如在display函数中,主要的绘制在这实现,包括贪吃蛇身体的绘制和食物的随机出现与绘制:

1.	void display()  
2.	{  
3.	    glClear(GL_COLOR_BUFFER_BIT);  
4.	    glMatrixMode(GL_PROJECTION);  
5.	    glLoadIdentity();  
6.	    gluOrtho2D(0, 40, 0, 40);  
7.	    drawText("Press p to start game or pause", 25, 35, 0.0, 0.0, 0.0);
8.	    drawText("See more in the console", 25, 34, 0.0, 0.0, 0.0);  
9.	    glColor3f(0.0f, 0.0f, 0.0f);  
10.	    glBegin(GL_LINES);  
11.	    glVertex2f(0, 20.0f);  
12.	    glVertex2f(40, 20.0f);  
13.	    glVertex2f(20.0f, 0);  
14.	    glVertex2f(20.0f, 40);  
15.	    glEnd();  
16.	    glMatrixMode(GL_MODELVIEW);  
17.	    drawSnake();  
18.	    drawFood();  
19.	    glutSwapBuffers();  
20.	}

回到刚才的snakestart,里面的glutTimerFunc设置了刷新频率,回调函数设置如下,这里实际上就是以定期的刷屏实现了贪吃蛇的移动效果:

1.	void TimerFunc(int val)  
2.	    if (!paused)  
3.	    {  
4.	        moveSnake(direction);  
5.	    }  
6.	    glutTimerFunc(100, TimerFunc, 0);//以后会再来一次 

可以看到,只要不是在暂停状态下,函数就会实际调用。执行结束后,由于moveSnake里有glutPostRedisplay,会执行display。由于上一行的glutTimerFunc,会继续执行TimerFunc。

我们知道glutMainLoop的作用是将处理函数按照某种顺序执行,没有新事件则会保持等待。在有glutTimerFunc时,使用glutMainLoop并不是使diplay无限调用(可以用cout验证),只有在状态改变时(如鼠标点击)才会调用display,但即使没有调用,还是会使得窗口一直保持显示而不会退出。加入glutTimerFunc后,相当于设立了一个计时器,如果在里面加入glutPostRedisplay,则会定时调用display。glutTimerFunc执行与display并行,即计时不会等到diplay完成后才开始,如果diplay未完成则等待(可以在TimerFunc里插入cout验证)。

关于贪吃蛇游戏,还有最重要的一点是撞墙算法和吃到食物的。撞墙即代表游戏结束,吃到食物则会使身体长度+1:

1.	if (snake_body[0].first <= 0 || snake_body[0].first >= 40 - 1 || snake_body[0].second <= 0 || snake_body[0].second >= 40 - 1)  
2.	    {  
3.	        cout << "由于撞到了边界,游戏结束了" << endl;  
4.	        cout << "您的最终得分为: " << score << endl;  
5.	        exit(0);  
6.	    }  
7.	    int grow = 0;  
8.	    if (snake_body[0].first + delX == food_pos[0] && snake_body[0].second + delY == food_pos[1])  
9.	    {  
10.	        grow = 1;  
11.	        score++;  
12.	        foodAvailable = 0;  
13.	    }  
14.	    snake_body.push_front({ snake_body[0].first + delX,snake_body[0].second + delY });  
15.	    if (!grow)  
16.	    {  
17.	        snake_body.pop_back();  
18.	    }

除此之外还有一些比较重要的算法,例如随机在屏幕中某一位置生成食物的算法。该算法的重点是随机生成,使用rand函数随机生成x、y坐标后,将其赋给食物数组food_pos,后续再调用专门的食物绘制函数food_texture进行绘制,达到了封装的效果:

1.	void drawFood()  
2.	{  
3.	    if (!foodAvailable)  
4.	    {  
5.	        int fx = rand() % (40 - 2) + 1;  
6.	        int fy = rand() % (40 - 2) + 1;  
7.	        int overlap = 1;  
8.	        while (overlap)// make sure no overlap of food with snake body  
9.	        {  
10.	            for (auto part : snake_body)  
11.	            {  
12.	                if (part.first == fx && part.second == fy)  
13.	                {  
14.	                    fx = rand() % 40 + 1, fy = rand() % 40 + 1;  
15.	                    break;  
16.	                }  
17.	            }  
18.	            overlap = 0;  
19.	            food_pos[0] = fx;  
20.	            food_pos[1] = fy;  
21.	        }  
22.	    }  
23.	    foodAvailable = 1;  
24.	    glColor3f(0, 0, 0);  
25.	    food_texture(food_pos[0], food_pos[1]);  
26.	  
27.	} 
28.	void food_texture(int x, int y)  
29.	{  
30.	    glBegin(GL_POLYGON);  
31.	    glVertex2f(x, y);  
32.	    glVertex2f(x, y + 1);  
33.	    glVertex2f(x + 1, y + 1);  
34.	    glVertex2f(x + 1, y);  
35.	    glEnd();  
36.	} 

大家对上述程序有疑问的话可以私信询问。

你可能感兴趣的:(游戏,OpenGL,c++,学习,经验分享)