You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

GLUT框架下按下ESC键后类人脸图形无法按预期循环右移的问题排查与解决请求

问题分析与解决方案

首先,你的问题核心在于误用了阻塞式的Sleep和for循环。GLUT是单线程的事件驱动框架,当你在moveright函数里调用Sleep(1000)时,整个GLUT主循环会被彻底卡住,无法处理重绘请求(glutPostRedisplay的效果要等到主循环空闲时才会生效)。所以尽管你的坐标变量已经更新,但直到整个for循环执行完毕,窗口才会一次性刷新,而且最后还调用了glutDestroyWindow(1)直接关闭窗口,自然看不到任何移动过程。

修复步骤

我们需要改用GLUT的glutTimerFunc来实现逐次延迟移动,这是GLUT框架下处理定时任务的标准方式,不会阻塞主循环。具体做法如下:

  1. 移除moveright里的for循环和Sleep,改成每次定时器触发时完成一次移动,然后根据剩余次数决定是否继续设置下一个定时器。
  2. 调整facemove里的定时器调用,传递初始的移动次数(比如5次)。
  3. 按需保留或移除glutDestroyWindow调用(如果不需要移动完成后关闭窗口,就删掉它)。

修改后的完整代码

#include <iostream>
#include <cstdlib>
#include <GL/glut.h>
using namespace std;

void display();
void facemove(unsigned char key, int x, int y);
void moveright(int remainingMoves);

// y axis of eyes
float eyelower = 0.25f;
float eyeupper = 0.50f;
// left eye
float leftx1 = -0.50f;
float leftx2 = -0.10f;
float leftx3 = -0.30f;
// right eye
float rightx1 = 0.10f;
float rightx2 = 0.50f;
float rightx3 = 0.30f;
// mouth
float mouthx1 = -0.15f;
float mouthx2 = 0.15f;
float mouthy1 = 0.0f;
// default color for left eye
int lrdefault = 255;
int lgdefault = 215;
int lbdefault = 0;
// default color for right eye
int rrdefault = 255;
int rgdefault = 215;
int rbdefault = 0;

int main(int argc, char** argv){
    glutInit(&argc, argv);
    glutInitWindowSize(500,500);
    glutInitWindowPosition(0,0);
    glutCreateWindow("My First Program");
    glutDisplayFunc(display);
    glutKeyboardFunc(facemove);
    glutMainLoop();
    return 0;
}

void display(){
    glClear(GL_COLOR_BUFFER_BIT);
    glBegin(GL_POLYGON);
    glColor3ub(0,102,0);
    glVertex2f(-0.98f, -0.98f);
    glVertex2f(-0.98f, 0.98f);
    glVertex2f(0.98f, 0.98f);
    glVertex2f(0.98f, -0.98f);
    glEnd();
    glBegin(GL_TRIANGLES);
    glColor3ub(lrdefault, lgdefault, lbdefault);
    glVertex2f(leftx1, eyelower);
    glVertex2f(leftx2, eyelower);
    glVertex2f(leftx3, eyeupper);
    glEnd();
    glBegin(GL_TRIANGLES);
    glColor3ub(rrdefault, rgdefault, rbdefault);
    glVertex2f(rightx1, eyelower);
    glVertex2f(rightx2, eyelower);
    glVertex2f(rightx3, eyeupper);
    glEnd();
    glColor3ub(255, 215, 0);
    glLineWidth(5.0f);
    glBegin(GL_LINES);
    glVertex2f(mouthx1,mouthy1);
    glVertex2f(mouthx2, mouthy1);
    glEnd();
    glFlush();
}

void facemove(unsigned char key, int x, int y){
    switch(key){
        case 27:
            // 先延迟5秒,然后开始第一次移动,剩余5次
            glutTimerFunc(5000, moveright, 5);
            break;
        default:
            break;
    }
}

void moveright(int remainingMoves){
    if(remainingMoves <= 0){
        // 移动完成,若需要可在这里销毁窗口
        // glutDestroyWindow(glutGetWindow());
        return;
    }

    // 移动所有面部元素的坐标
    leftx1 += .09f;
    leftx2 += .09f;
    leftx3 += .09f;
    rightx1 += .09f;
    rightx2 += .09f;
    rightx3 += .09f;
    eyelower += .09f;
    eyeupper += .09f;
    mouthx1 += .09f;
    mouthx2 += .09f;

    // 请求窗口重绘
    glutPostRedisplay();
    cout << "已完成移动次数: " << 5 - remainingMoves + 1 << endl;

    // 设置下一次定时器,1秒后触发,剩余次数减1
    glutTimerFunc(1000, moveright, remainingMoves - 1);
}

关键改动说明

  • 替换阻塞逻辑:用glutTimerFunc替代Sleep和for循环,每次定时器触发时完成一次移动,再递归设置下一次定时器,这样不会阻塞GLUT主循环,重绘请求能及时被处理,你就能看到逐次移动的效果。
  • 剩余次数跟踪:通过定时器的value参数传递剩余移动次数,当次数为0时停止移动逻辑。
  • 移除无效代码:原facemove的default分支里,glutPostRedisplay放在break之后永远不会执行,所以直接移除了这段无效代码。

这样修改后,按下ESC键后会先等待5秒,然后每秒向右移动一次人脸,共5次,你能清晰看到每一步的移动效果。

内容的提问来源于stack exchange,提问作者Austin Gyan Marbella

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 13:52:34