我正在尝试找出一种在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;
}
答案 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或某些东西被实际背后的东西所吸引。
希望我没有切入口,这篇文章对你有所帮助!
古德勒克!