Box2D C++ 力和冲量

~~~~我的生活,我的点点滴滴!!


力和冲量(Forces and impulses)



让物体移动,需要对其施加力或者冲量。可以通过时间的不断积累对物体施加力的作用来改变物体的运动,然而冲量作用于物体则会立刻

改变物体的速度。举个例子,想象一下现在你的车坏了,你想推车,可以选择驱动另外一辆车缓慢开向这辆坏了的车,当两辆车的保险杠

接触之后,继续对这辆车施加推力,然后通过时间不断的积累慢慢的让其移动。或者也可以用冲量,驱动一辆完好的车全速驶向这辆坏了

车。具体使用哪种方法取决于你。


也可以通过简单设置物体的位置来瞬间“曲速(参见Warpdrive)”物体。在游戏中你可能想有一个瞬移的特性,但是你要知道在真正的物理

世界当中并不存在这样一种特性!Box2D的全部侧重点是让所模拟的物体看起来更真实,基于这一点考虑我会建议你尽量使用力和冲量来移

动物体。大多数时候这么做看起来貌似过于严谨,但是在真实的世界里所有事情的发生都是通过力和冲量的,除非你就是想创建一个不是

真实世界里的特性(瞬移,等等),要三思!而且如果你这么做下去的话,可能会给你带来更多的麻烦。



角运动也可以通过力和冲量来控制,效果就像上面提到的缓慢/瞬间的线性版本一样。角力矩也称为扭矩(torque)。
可以想象成转动强度,

就像你拧瓶盖儿一样-瓶盖不会跑出去,而且你可以持续对瓶盖施加作用力(扭矩,torque)。



我们将创建三个物体,使用上面提到的两种力来分别作用于它们平移或扭曲(twist)它们,代码如下:

//.h中
	//定义了三个物体,全为指针对象
	b2Body *m_body[3];

//.cpp中
	b2Vec2 gravity(0, 0);
	/*********************start*************************/
	//定义一个物体的基本属性,他基本包含了我们所知现实世界物体的所有属性
	b2BodyDef bodyDef;
	//设置一个动态物体
	bodyDef.type = b2_dynamicBody;
	bodyDef.angle = 0;
	//形状
	b2PolygonShape boxShape;
	//创建一个2x2的正方形盒子
	boxShape.SetAsBox(1,1);

	//定制器
	b2FixtureDef fixtureDef;
	fixtureDef.shape = &boxShape;
	fixtureDef.density = 10;

	for(int i = 0 ;i < 3; ++ i)
	{
		bodyDef.position.Set( -10 + i * 10, 20 );
		m_body[i] = m_world->CreateBody(&bodyDef);
		m_body[i]->CreateFixture(&fixtureDef);
	}
	///*************到底就一个正方形物体产生了******************/
	
	//产生一条水平线
	b2BodyDef lineDef;
	lineDef.type = b2_staticBody;
	lineDef.position.Set(0,0);

	b2EdgeShape edgeShape;
	edgeShape.Set(b2Vec2(-20,0), b2Vec2(20,0));

	b2FixtureDef edgeFixture;
	edgeFixture.shape = &edgeShape;

	b2Body *lineBody = m_world->CreateBody(&lineDef);
	lineBody->CreateFixture(&edgeFixture);

这样就创建了三个盒子,他们会在重力的作用下自然下落,这段代码会为下面的两种力矩方式提供测试环境


1、线性运动(Linear movement)

我们需要一个不使用鼠标就能影响物体运动的方法。我们可以利用testbed框架中键盘输入特性的时候了。覆盖Test类中Keyboard方法,

为每个物体定义不同的方法。

//.h中
	void Keyboard(unsigned char key)override;

	void Step(Settings* settings)override;

	bool m_forceOn;
	
//.cpp中

//构造函数中初始化 
m_forceOn = false;

void UserTest::Keyboard(unsigned char key)
{
	switch (key)
	{
	case 'q':
		{
			cout << "q" << endl;
			m_forceOn = !m_forceOn;
		}
		break;

	case 'w':
		{
			cout << "w" << endl;
			//向上直接用力(冲量)
			m_body[1]->ApplyLinearImpulse(b2Vec2(0,30), m_body[1]->GetWorldCenter());
		}
		break;

	case 'e':
		{
			cout << "e" << endl;
			//瞬间或曲速(表示特别快)到目标地
			m_body[2]->SetTransform(b2Vec2(10,30), 0);
		}
		break;

	default:
		Test::Keyboard(key);
	}
}

void UserTest::Step(Settings* settings)
{
	if( m_forceOn )
	{
		//向上渐渐的力,起始点为了物体的质心在世界中的位置(力)
		m_body[0]->ApplyForce(b2Vec2(0,30), m_body[0]->GetWorldCenter());
	}

	Test::Step(settings);
}

其中SetTransform方法已经在物体(bodies)话题中讨论过了。ApplyForce和ApplyLinearImpulse方法传入了两个参数,第一个参数应该是所

施加的力的方向,本例中是线性增加。运行测试然后按下q/w/e按键。受到冲量作用的物体就像被什么东西突然撞到一样。这个运动的物体

被瞬间移动到一个新位置,但是注意它仍然保持了原来的线性和角速度。我们对物体施加了作用力之后到底发生了些什么呢?Keyboard

方法只有当我们按下按键的时候才会被调用一次,不是每个时间步长都会调用。我们使用了相同大小(50)的力和冲量,但是为什么力(ApplyForce)

的效果看起来比冲量不明显呢?嗯,那是因为重力也是作用力。试着取消重力作用或许能让问题的答案更清晰一些。原因是因为力在每个

时间步长(timestep)上让物体上移一点,随后在重力的作用下物体又下降一点。就这样不断的上下上下的纠结。那么对于冲量来说,在重力

对物体进行干扰之前完成了所有的工作。失重状态下,试着让力作用大概1秒钟时间,紧接着停止施加作用力。你会注意到,一秒钟力的作用

效果和冲量的作用效果有相同的速度。现在让我们来看看之前在施加作用力/冲量方法中所忽略的第二参数(m_body[0]->GetWorldCenter())

是什么意思?到目前为止我们一直使用物体自身可以获取质心的GetWorldCenter()方法来设置此参数。正如我们所看到的,当作用力作用于质心

的时候并不会引起物体的旋转。我们稍微偏移一下之前施加力/冲量的作用点。改变一下ApplyForce和ApplyLinearImpulse的作用点:


//上面我们设置盒子为了1x1(实际是2x2大小)这里设置b2Vec2(1,1)为右上角
m_body[1]->GetWorldPoint(b2Vec2(1,1)

这次,你应该会看到当盒子们运动的时候,会发生旋转。GetWorldPoint()方法用来将物体自身的坐标(物体坐标系
(body coordinates))转换到

世界坐标系中,所以即便盒子发生旋转之后我们依然可以把力作用于盒子的右上角。可能会被认为是“拽着盒子角把盒子拎起来”,但是作用力

并不是作用在可见的矩形定制器上-力和冲量是作用于物体上,不是它的定制器上。力可以轻松的作用于任何之前的点上,即便是没有定制器

(fixtures)的空点上。


2、角运动(Angular movement)

角运动被角力矩(扭矩,torque)和角动量所控制。它们的行为和线性运动相似,力是缓慢作用的而角动量是瞬间作用的。我们继续在Keyboard

中添加测试代码:

switch (key)
	{
	case 'q':
		{
			cout << "q" << endl;
			m_forceOn = !m_forceOn;
			m_body[0]->ApplyTorque( 20 );
		}
		break;

	case 'w':
		{
			cout << "w" << endl;
			//向上直接用力(冲量)
			m_body[1]->ApplyLinearImpulse(b2Vec2(0,30), m_body[1]->GetWorldPoint(b2Vec2(1,1)));
			//逆时针旋转(冲量)---这里我故意写成m_body[0]下面的gif图片会看到效果
			m_body[0]->ApplyAngularImpulse( 20 );
		}
		break;

	case 'e':
		{
			cout << "e" << endl;
			//瞬间或曲速(表示特别快)到目标地
			m_body[2]->SetTransform(b2Vec2(10,30), 0);
		}
		break;

	default:
		Test::Keyboard(key);
	}


在长按住w后,你会发现中间的小盒子旋转向上,左边的盒子也在旋转,正常左边的盒子不会发生移动的,但是它们还是会有一点点移动,这是

因为它和地面之间有摩擦并且运动起来就像方轮子一样。为了能够更好的说明扭矩和角动量到底都做了些什么,关闭重力效果。在失重环境中,

我们可以看到对于转动力矩/角动量方法为什么只需要一个参数-既然不会引起线性运动,那么唯一我们需要指定的就是转动的方向。由于物体的

转动总是绕着物体质心展开,所以不会像上面线性力矩那样产生任何偏差。和线性力矩一样,传入相同的参数,ApplyTorque执行一秒钟以后会和

ApplyAngularImpulse立即执行所产生的角速度相同。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Box2D是一个用于物理模拟的开源库,可以用于模拟刚体的运动和碰撞等物理效果。下面是将Box2D库文件添加到DevC++项目中的步骤: 1. 下载Box2D库文件:你可以从Box2D的官方网站(https://box2d.org/)下载最新版本的库文件。选择适合你操作系统的版本,并下载压缩包。 2. 解压库文件:将下载的压缩包解压到一个你喜欢的位置,得到一个包含Box2D库文件的文件夹。 3. 打开DevC++:启动DevC++集成开发环境。 4. 创建一个新项目:选择“文件”菜单中的“新建”选项,然后选择“项目”。 5. 选择项目类型:在弹出的对话框中,选择“空项目”。 6. 添加Box2D库文件:右键点击项目名称,选择“属性”选项。在属性对话框中,选择“参数”选项卡。在“链接器”选项卡中,点击“添加库或对象文件”按钮。浏览到你解压的Box2D库文件夹中,选择其中的lib文件夹,然后选择适合你编译器的版本(通常是Debug或Release)。在该文件夹中,选择libbox2d.a(对于Linux)或box2d.lib(对于Windows)文件。点击“打开”按钮。 7. 添加Box2D头文件路径:在属性对话框中,选择“目录”选项卡。点击“添加”按钮,浏览到你解压的Box2D库文件夹中,选择其中的include文件夹。点击“打开”按钮。 8. 编写代码:现在你可以在DevC++中编写使用Box2D库的代码了。记得在代码中包含Box2D的头文件,并使用Box2D的命名空间。 9. 编译和运行:保存你的代码,并点击DevC++工具栏上的“编译并运行”按钮,或者按下F9键进行编译和运行。 希望以上步骤对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值