在OpenGL中创建一个球体动画,使球体在窗口内做自由落体运动,并在撞击地面后能够返回原来高度

这是计算机图形学基础的一道单元练习题,看题的时候觉得没什么,写出来才发现其中大有门道,其中有几个值得关注的地方:

  • 首先如果你是以窗口底部为地面的话,你会发现小球在第二次下落时无法回弹,这就很恶心了,做了很多无谓的尝试查了一些资料最后也只是找到了一个合适的位置让小球可以一直下落和回弹。
  • 还有一个细节就是我初始化小球y坐标为9.0001,而其回弹的最高位置是9.0,如果初始化小球y坐标也是9.0,小球仍然会出现上面那种情况。
  • 其次就是在模拟重力加速度以及放入实际的牛顿那个重力公式中的时候,方向很重要,注意是速度的方向在回弹和下落初的变换,重力加速度始终是向下的。
  • 最后就是用glutTimerFunc(2, timer, 0);指定定时器回调函数让小球自己去动。计算自由下落公式的相隔时间是2ms。所以把计时器也设为2ms吧。效果还不错。

为了看看是不是真的自由下落没有损失,我还在起始点和终点画了两条红线便于观察:
在这里插入图片描述
代码:

#include <windows.h>
#include <GL/freeglut.h>
#define G 9.8
bool direction = true;
double t = 0.002;
struct Ball{//球的结构体
	GLdouble y;
	GLdouble vy;
};
Ball ball;
void init(void){
	//初始化球体属性
	ball.y = 9.00001 ; 
	ball.vy = 0.0 ;
	glClearColor(0.0,0.0,0.0,0.0);
	
}
void display(void){
	glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
	glPushMatrix();
		glColor3f(1.0,0.0,0.0);
		glBegin(GL_LINES);
			glVertex2f(-5.0,9.0);
			glVertex2f(5.0,9.0);
			glVertex2f(-5.0,-3.0);
			glVertex2f(5.0,-3.0);
		glEnd();
		glColor3f(1.0,1.0,0.0);
		glTranslated(0,ball.y,0); //将绘图中心移动到球体的中心
		glutSolidSphere(0.5,50,50); //绘制一个球体
		if(direction){
			ball.y = ball.y-(ball.vy*t+0.5*G*t*t); //根据牛顿运动定律计算出球的位移公式
			ball.vy = ball.vy + G*t; //根据牛顿运动定律计算出球体的速度
			if(ball.y <=-3.0){ 
				direction = false; //触发转向条件,改变direction的值,使球体运动方向改变 
			} 
		}else{ 
			ball.y = ball.y + (ball.vy*t-0.5*G*t*t); 
			ball.vy = ball.vy-G*t; 
			if(ball.y >= 9.0){
				direction = true;
			}
		}
	glPopMatrix();
	//交换前后缓冲区
	glutSwapBuffers();
}
void timer(int value)
{
	glutPostRedisplay();
	glutTimerFunc(2,timer, 0);
}
void reshape(int w,int h){
	glViewport(0,0,(GLsizei)w,(GLsizei)h);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	if(w<=h)
		glOrtho(-15,15,-15*(GLfloat)h/(GLfloat)w,15*(GLfloat)h/(GLfloat)w,-15,15);
	else
		glOrtho(-15*(GLfloat)h/(GLfloat)w,15*(GLfloat)h/(GLfloat)w,-15,15,-15,15);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}
int main(int argc,char** argv){
	glutInit(&argc,argv);
	glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB|GLUT_DEPTH);
	glutInitWindowSize(600,600);
	glutInitWindowPosition(450,100);
	glutCreateWindow("小球自由落体");
	init();
	glutDisplayFunc(display);
	glutReshapeFunc(reshape);
	//永动机
	glutTimerFunc(2, timer, 0);
	glutMainLoop();
	return 0;
}
  • 10
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,您可以参考以下的代码实现: ```csharp using System; using System.Drawing; using System.Windows.Forms; namespace FreeFallBall { public partial class Form1 : Form { private const int ballSize = 50; // 小球的大小 private const int groundHeight = 100; // 地面高度 private const double gravity = 9.8; // 重力加速度 private double initialVelocity = 0; // 初速度 private double verticalPosition = 0; // 垂直位置 private double elapsedTime = 0; // 运动时间 private double timeInterval = 0.1; // 时间间隔 private bool isBallMoving = false; // 判断小球是否在运动 public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { // 将小球放置在窗体心的顶部位置 verticalPosition = -ballSize; ball.Location = new Point((ClientSize.Width - ballSize) / 2, (int)verticalPosition); } private void startButton_Click(object sender, EventArgs e) { if (!isBallMoving) { isBallMoving = true; initialVelocity = Convert.ToDouble(initialVelocityTextBox.Text); timer.Start(); } } private void timer_Tick(object sender, EventArgs e) { // 计算小球的运动状态并更新位置 elapsedTime += timeInterval; verticalPosition = 0.5 * gravity * elapsedTime * elapsedTime + initialVelocity * elapsedTime; ball.Location = new Point((ClientSize.Width - ballSize) / 2, (int)(ClientSize.Height - ballSize - groundHeight - verticalPosition)); // 判断小球是否落地停止运动 if (verticalPosition >= 0 && ball.Location.Y >= ClientSize.Height - ballSize - groundHeight) { isBallMoving = false; timer.Stop(); } } } } ``` 在窗体添加一个 `PictureBox` 控件,并设置其大小为 50x50(即小球的大小),命名为 `ball`。然后添加一个 `Button` 控件,命名为 `startButton`,用于开始模拟小球自由落体运动。还需要添加一个 `TextBox` 控件,用于输入小球的初始速度,命名为 `initialVelocityTextBox`。 在窗体的 `Load` 事件,将小球放置在窗体心的顶部位置。 在 `startButton` 的 `Click` 事件,获取小球的初始速度,并启动定时器 `timer`,开始模拟小球的自由落体运动。 在 `timer` 的 `Tick` 事件,计算小球当前的位置,并更新其在窗体的位置。如果小球落地停止运动,则停止定时器。 需要注意的是,定时器的时间间隔 `timeInterval` 要足够小,以保证小球的运动状态能够得到精确的计算。同时,为了简化计算,此处假设小球下落的过程没有空气阻力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值