基于GLUT库的打砖块游戏优化:实现小球固定速度持续移动
打砖块游戏持续运动优化方案
当前游戏只能按键逐帧运行的核心原因是:原代码仅在键盘按键触发时才发起重绘,且动画逻辑耦合在myDisplay的单次for循环内,没有定时自动重绘的机制。具体优化方案如下:
修改步骤
- 新增定时器回调函数,设置固定刷新间隔(16ms对应约60帧刷新率),定时触发重绘,摆脱对按键事件的依赖
- 移除
myDisplay函数内的外层for循环,单次重绘仅执行一帧的坐标更新、绘制、碰撞检测逻辑 - 主函数中注册定时器回调,启动自动刷新循环
- 修复原代码绘制挡板后颜色未复位的问题,避免小球变成黑色
- 原有挡板操作、碰撞检测、得分逻辑无需改动,可直接兼容
完整优化后代码
#include<stdio.h> #include<GL/glut.h> #include<math.h> #define pi 3.142857 // 全局声明 // c和d分别统计按键'b'和'n'的按下次数 // left和right为可移动挡板的左右边界坐标 int c = 0, d = 0, left = 0, right = 0; int m = 0, j = 1, flag1 = 0, l = 1, flag2 = 0, n = 0, score = 0, count = 1; // 定时器回调函数,实现定时重绘 void timer(int value) { glutPostRedisplay(); glutTimerFunc(16, timer, 0); // 16ms刷新一次,约60帧 } // 初始化函数 void myInit (void) { // 将背景色重置为白色(RGB三个通道值均为1.0) glClearColor(1.0, 1.0, 1.0, 0.0); // 设置绘制颜色为红色(RGB模型中仅R通道值为1.0) glColor3f(1.0f, 0.0f, 0.0f); // 设置点的宽度为1单位 glPointSize(1.0); glMatrixMode(GL_PROJECTION); glLoadIdentity(); // 设置X、Y方向的窗口坐标范围 gluOrtho2D(-620.0, 620.0, -340.0, 340.0); } // 键盘事件响应函数,按键按下时触发 void keyboard(unsigned char key, int x, int y) { left = -200 + 200 * (d - c); right = 200 + 200 * (d - c); // 当挡板触碰窗口左边界时,后续按b键不会再左移,仅可按n键右移 if (left == -600) { // 110为字符'n'的ASCII值,按下n键时d自增 if (key == 110) d++; } // 当挡板触碰窗口右边界时,后续按n键不会再右移,仅可按b键左移 else if (right == 600) { // 98为字符'b'的ASCII值,按下b键时c自增 if (key == 98) c++; } // 挡板处于窗口中间区域时,可按对应按键左右移动 else { if (key == 98) c++; if (key == 110) d++; } glutPostRedisplay(); } void myDisplay(void) { // x、y存储圆周上的点坐标 int x, y; glClear(GL_COLOR_BUFFER_BIT); glBegin(GL_LINE_STRIP); // i记录角度值 float i = 0; // m的变化对应垂直方向移动,n的变化对应水平方向移动 m = m + 6; n = n + 4; // 绘制圆心在(0, 12)的圆,遍历角度到2π即360度 while (i <= 2 * pi) { y = 12 + 20 * cos(i); x = 20 * sin(i); i = i + 0.1; // flag1为0表示小球向上移动,为1表示向下移动 if (m == 288 && flag1 == 0) { j = -1; m = -288; flag1 = 1; score++; } if (m == 288 && flag1 == 1) { j = 1; m = -288; flag1 = 0; } // flag2为0表示小球向右移动,为1表示向左移动 if (n == 580 && flag2 == 0) { l = -1; n = -580; flag2 = 1; } if (n == 580 && flag2 == 1) { l = 1; n = -580; flag2 = 0; } // 小球运动坐标计算 glVertex2i((x - l * n), (y - j * m)); } glEnd(); // 绘制游戏窗口外框矩形 glBegin(GL_LINE_LOOP); glVertex2i(-600, -320); glVertex2i(-600, 320); glVertex2i(600, 320); glVertex2i(600, -320); glEnd(); // 绘制接球用的底部矩形挡板 glColor3f(0,0,0); glBegin(GL_LINE_LOOP); left = -200 + 200 * (d - c); right = 200 + 200 * (d - c); glVertex2i(left, -315); glVertex2i(left, -295); glVertex2i(right, -295); glVertex2i(right, -315); glEnd(); // 恢复小球颜色为红色,避免下一帧绘制小球变成黑色 glColor3f(1.0f, 0.0f, 0.0f); // 检测下落的小球是否被挡板接住 if ((j * m) == 276) { if ((left > ((-1 * l * n) + 20)) || (right < (-1 * l * n) - 20)) { printf("Game Over !!!\nYour Score is :\t%d\n", score); exit(0); } } glutSwapBuffers(); } // 主函数 int main (int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA); // 声明窗口尺寸 glutInitWindowSize(1100, 600); // 声明窗口位置为(0,0),即左下角对应坐标(0,0) glutInitWindowPosition(0, 0); // 设置窗口名称 glutCreateWindow("Game"); // 注册键盘事件回调函数 glutKeyboardFunc(keyboard); // 注册定时器回调 glutTimerFunc(0, timer, 0); // 调用初始化函数 myInit(); glutDisplayFunc(myDisplay); glutMainLoop(); }
内容的提问来源于stack exchange,提问作者Eikichi Onizuka
相关产品推荐
相关产品推荐

