我正在尝试找出一种在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;
}
最佳答案
因此,首先,我们要使生活更轻松,您应该尝试将蠕虫抽象到一个类。我假设您以后可能会继续进行开发,但是无论如何它仍然是一个很好的实践。这也将使我们的抽奖更加容易。
好的,假设我们现在有了Worm
类,该类将具有自己的draw函数,我们希望尝试尽可能简单地将main中display()
函数中的draw调用保留下来。想象一下,如果您想绘制另一种蠕虫,该怎么办。
因此,在您的蠕虫类中,您的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()
注意,该循环也将是半循环-无限循环。它会在某个标志为true的情况下运行,一旦蠕虫蠕动到足够程度,您就可以终止它。 :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上都没有过剩的设置。但是,如果这不能完全满足您的要求,请给我一些评论,我下班回家时可以看看。
最后要注意的一点是,您也将在游戏循环中调用move函数,现在对于您的游戏循环,您可能只需要执行while循环即可,但是最终您可以将其设置为每次更新X次秒,每秒绘制Y次。
需要注意的一件事是,因为每帧画的东西不多,所以不会有所作为。您可以继续绘制蠕虫,这就是
gLClear()
函数正在为您做的事情,它将清除当前颜色缓冲区中的所有内容,如果您正在忙于显式使用3D的应用程序,则需要添加深度缓冲区,如下所示:好吧,否则事情就不会以正确的顺序绘制,您可能会发生Z战或某些事情被其背后的事情所覆盖。希望我不切题,并且这篇文章对您可能有价值!
祝好运!