OpenGL中的蠕虫爬行动作?

时间:2014-09-24 22:03:00

标签: c++ opengl animation infinite-loop

我正在尝试找出一种在OpenGL中执行以下行为的有效方法。

我正在制作一个类似蠕虫的家伙(基本上我想要一个有某种可见眼睛的矩形 - 没什么复杂的),它应该通过在前面扩展到其长度的两倍来移动,并从后面缩回到其原始大小。当蠕虫到达窗口边缘时,它会反转方向。

我在使动作正确方面遇到了很大的困难,并且在定位眼睛时遇到了一些小的困难。如果我简单地用相对位置一个接一个地绘制两个多边形,我可以期望后者被涂在前者上吗?我此刻的动作呈现出一个无限循环,我无法在概念上改变另一种方法。我无法弄清楚循环结构是否具有双倍/收缩运动并且有效地接近终止。

以下当前代码:

#define GLUT_DISABLE_ATEXIT_HACK
#include <GL/glut.h>
#include <GL/gl.h>

float wormX = 0;
float wormY = 0;
float wormWidth = 100;
float wormHeight = 75;
bool wormCrawl = true;

void timer( int value )
{
const int w = glutGet(GLUT_WINDOW_WIDTH);
if( wormX + wormWidth >= w / 2 ) //If worm hits edge, reverse direction!
{
    wormX = 2;
}

while( wormCrawl )
{
    wormX += 2; //Move the worm
    wormWidth = 2*wormWidth; //Extend the front
    wormWidth = (1/2)*wormWidth; //Retract the back

}

glutTimerFunc( 16, timer, 0 );
glutPostRedisplay();
}

void display()
{
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);

const int w = glutGet(GLUT_WINDOW_WIDTH);
const int h = glutGet(GLUT_WINDOW_HEIGHT);

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho( -w/2, w/2, -h/2, h/2, -1.0, 1.0);

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

const float leftCorner = wormX;
const float rightCorner = leftCorner + wormWidth;
const float bottomCorner = wormY;
const float topCorner = bottomCorner + wormHeight;
//Worm
glBegin(GL_POLYGON);
    glColor3f(0.0, 1.0, 0.0);
    glVertex2d(leftCorner, topCorner);
    glVertex2d(rightCorner, topCorner);
    glVertex2d(rightCorner, bottomCorner);
    glVertex2d(leftCorner, bottomCorner);
glEnd();
//Worm eye
glBegin(GL_POLYGON);
    glColor3f(0.0, 0.0, 0.0);
    glVertex2d(leftCorner, topCorner);
    glVertex2d(leftCorner + 10, topCorner);
    glVertex2d(leftCorner + 10, bottomCorner);
    glVertex2d(leftCorner, bottomCorner);
glEnd();

glutSwapBuffers();
}

int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(500, 500);
glutInitWindowPosition(0, 0);
glutCreateWindow ("Inchworm Crawl");

glutDisplayFunc(display);
glutTimerFunc( 0, timer, 0 );
glutMainLoop();

return 0;
}

1 个答案:

答案 0 :(得分:1)

首先,我们希望让生活更轻松,您应该尝试将您的蠕虫抽象到一个类。我假设你可能想继续开发这个,但无论如何它还是很好的做法。这也将使我们的绘图调用更容易。

好的,假设我们现在有Worm类,那个类将有自己的绘制函数,我们想尽可能简单地在我们的主要display()函数中保持我们的绘制调用。想象一下,如果你想绘制另一个蠕虫,你必须做什么。

所以在你的蠕虫类中你的draw()方法看起来像这样:

void Worm::draw()
{
    const float leftCorner = wormX;
    const float rightCorner = leftCorner + wormWidth;
    const float bottomCorner = wormY;
    const float topCorner = bottomCorner + wormHeight;
    //Worm
    glBegin(GL_POLYGON);
        glColor3f(0.0, 1.0, 0.0);
        glVertex2d(leftCorner, topCorner);
        glVertex2d(rightCorner, topCorner);
        glVertex2d(rightCorner, bottomCorner);
        glVertex2d(leftCorner, bottomCorner);
    glEnd();
    //Worm eye
    glBegin(GL_POLYGON);
        glColor3f(0.0, 0.0, 0.0);
        glVertex2d(leftCorner, topCorner);
        glVertex2d(leftCorner + 10, topCorner);
        glVertex2d(leftCorner + 10, bottomCorner);
        glVertex2d(leftCorner, bottomCorner);
    glEnd();
}

好的,这只是它的基础,但我仍然无法回答你的实际问题。我不确定您使用的是哪个版本的freeglut,但希望您拥有最新版本。一般来说,如果您计划的不仅仅是渲染,您应该尽量远离glutmainloop();。它基本上阻止你在渲染循环之外做任何逻辑,这实际上意味着程序中的所有内容都将被锁定到帧速率。相反,您应该在主函数中编写游戏循环,然后在每次想要渲染帧时调用glutmainloopevent()

所以现在更多的是移动,一旦你创建了你的游戏循环,逻辑上你可以把所有更新功能放在这里,在循环结束时,你可以调用glutmainloopevent()注意这个循环也将是一个半无限循环。它会在某些标志为真时运行,然后一旦你的蠕虫蠕动得足够就可以终止它。 :P

现在,对于我们的蠕虫类,我们可以添加更多功能来移动蠕虫并增加其宽度,我们可以称之为move()。而且为了简化事情,我们可以为我们的蠕虫添加一个标志,告诉我们他是否应该缩小或增长。这只是一个布尔值,在创建蠕虫对象时初始化为false。

void Worm::move(bool direction)
{
    if(growing)
    {
        wormWidth += 1;
        if(wormWidth > thresholdWidth)
        {
            growing = false;
        }
    }
    else
    {
        wormWidth += 1;
        if(wormWidth > thresholdWidth)
        {
            growing = false;
        }
    }
    if(direction)
    {
        wormx += 1;
    }
    else
    {
        wormx -= 1;
    }
}

现在我还没有对此进行过测试,但我认为它应该做一些接近你想要的事情。我目前在我的工作电脑上没有设置过剩,也没有openGL。但是,如果这不能完全满足您的要求,请给我一些评论,我可以在下班回家时看看。

最后要注意的是,你将在你的游戏循环中调用你的移动功能,现在对于你的游戏循环,你可能只需要一个while循环这样做,但最终你可以将它设置为仅更新X量每秒的次数,每秒绘制Y次。

有一点需要注意的是,因为你不是每帧不止一件事,所以不会有所作为。您可以继续绘制蠕虫,gLClear()函数正在为您做什么,它正在清除当前颜色缓冲区中的所有内容,如果您忙于使用明确使用3D的应用程序,则需要添加深度缓冲区也是如此,否则事情就不会以正确的顺序绘制出来,你可能会得到z-fighting或某些东西被实际背后的东西所吸引。

希望我没有切入口,这篇文章对你有所帮助!

古德勒克!