OpenGL贪吃蛇:tick函数坐标检测失效,仅能吃2次果实问题
解决OpenGL贪吃蛇只能吃2次果实的问题
嘿,我仔细看了你的代码,找到了几个导致蛇只能成功吃2次果实的关键问题,咱们一步步来修复:
1. 浮点数精确比较的致命问题
你的tick函数里直接用==比较两个GLfloat类型的坐标:
if(coord[0] == fruitcootd[0] && coord[1] == fruitcootd[1] && !eat)
浮点数在累加、计算过程中会产生精度误差(比如多次加减0.154后,数值可能变成0.30800000000000002而不是精确的0.308),直接用==判断相等大概率会失败,这就是吃几次后检测不到碰撞的核心原因。
修复方案:用误差范围判断,只要两个坐标的差值绝对值小于一个很小的阈值(比如0.01),就认为蛇吃到了果实:
void tick(int) { // 用阈值判断浮点数是否接近相等 bool xMatch = fabs(coord[0] - fruitcootd[0]) < 0.01; bool yMatch = fabs(coord[1] - fruitcootd[1]) < 0.01; if(xMatch && yMatch && !eat) { cout<<1<<endl; eat = 1; } glutPostRedisplay(); // 调整定时器间隔,1毫秒太频繁,改成100毫秒更合理 glutTimerFunc(100,tick,0); }
2. 果实随机生成逻辑的冗余与潜在问题
你的rdmfruit函数用循环累加0.154来生成位置,不仅冗余,还可能导致位置计算误差叠加。另外,当前逻辑没有判断生成的果实是否和蛇的位置重叠,可能出现果实直接刷在蛇身上的情况。
优化后的rdmfruit函数:
void rdmfruit() { // 直接计算位置,避免循环累加的误差 // 地图范围是-1到1,每个格子0.154,计算可用的格子数 int maxX = (int)((1.0 - (-1.0)) / 0.154); int maxY = maxX; // 生成随机格子索引,再转换为坐标 int xIndex = rand() % maxX; int yIndex = rand() % maxY; // 转换为GLfloat坐标,确保在-1到1范围内 fruitcootd[0] = -1.0 + xIndex * 0.154; fruitcootd[1] = -1.0 + yIndex * 0.154; // 额外检查:如果果实和蛇当前位置重叠,重新生成 while(fabs(fruitcootd[0] - coord[0]) < 0.01 && fabs(fruitcootd[1] - coord[1]) < 0.01) { xIndex = rand() % maxX; yIndex = rand() % maxY; fruitcootd[0] = -1.0 + xIndex * 0.154; fruitcootd[1] = -1.0 + yIndex * 0.154; } }
3. 定时器间隔设置不合理
你原来的glutTimerFunc(1,tick,0)设置1毫秒调用一次tick,这会导致CPU占用极高,而且逻辑执行过快,蛇的移动会变得难以控制。改成100毫秒左右(可以根据手感调整)更合理,上面的tick函数已经修改了这个值。
4. 初始状态的小问题
你的eat变量初始值是true,程序启动时会立即生成果实,但蛇初始位置是(0,0),有可能第一次生成的果实刚好在蛇身上,导致还没移动就触发吃果实的逻辑。可以在init函数里初始化一次果实,避免这种情况:
void init() { glClearColor(0,0,0,0); glClear(GL_COLOR_BUFFER_BIT); glDepthRange(100,100); // 初始化第一个果实 rdmfruit(); eat = 0; glutSwapBuffers(); }
同时修改fruit函数里的逻辑,去掉初始化果实的代码,因为init已经做了:
void fruit() { glPointSize(20); glColor3d(0,1,0); glBegin(GL_POINTS); glVertex2f(fruitcootd[0],fruitcootd[1]); glEnd(); }
最后,记得在main函数里添加随机数种子,不然每次生成的果实位置都是一样的:
int main(int argc, char *argv[]) { glutInit(&argc, argv); glutInitWindowSize(640,640); glutInitWindowPosition(10,10); glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); glutCreateWindow("Snake"); // 添加随机数种子 srand(time(NULL)); glutDisplayFunc(display); glutKeyboardFunc(key); glutTimerFunc(100,tick,0); init(); glutMainLoop(); return EXIT_SUCCESS; }
把这些修改整合后,蛇应该能正常多次吃果实了。
内容的提问来源于stack exchange,提问作者Hono
相关产品推荐
相关产品推荐

