您的位置:首页 > 编程语言 > C语言/C++

Box2D C++ 物理世界与自定义重力

2014-08-20 23:05 232 查看
~~~~我的生活,我的点点滴滴!!

1、世界

世界(Worlds)作为Box2D世界里主要的实体,在之前的讨论话题中已简单的介绍过。当你创建或者删除物体的时候,

可以调用世界里的方法来完成这些功能,所以世界也管理着所有对象的空间分配。这也就意味着世界非常重要,那

么就让我们来看看世界到底可以做些什么吧。

-定义重力加速度

-调用物理模拟

-发现定制器的作用域

-切断射线并找到相交的定制器

1.1、定义重力加速度

世界(world)的创建像其它普通类型一样,在构造函数里进行基本的设置,在设置时我们可以设置自己的重力加速器

//设置重力为0
b2Vec2 gravity(0, 0);

//构造一个世界对象
//b2World *world = new b2World(gravity);
//或者后面设置改变世界的重力
m_world->SetGravity(gravity);
//设定了当物体不受外界作用的时候是否允许睡眠
m_world->SetAllowSleeping(true);


1.2、调用物理模拟

重力加速度的数值大小会影响世界里的每个动态物体,睡眠参数设定了当物体不受外界作用的时候是否允许睡眠("sleep"),

此举可以提高程序运行的效率。如果这个参数为真(true),那么物体当不受作用时候会进入睡眠状态,直到有外界作用而

被叫醒(‘wake’),之后会重新对其进行模拟。例如来自其它物体的碰撞,产生外界作用力作用于物体上等等。一旦像上

面那样创建了一个世界,就可以像我们之前做的那样往世界里添加物体。为了让好玩的事情发生,我们需要不停的调用

Step()方法来模拟物理世界的运动。当然了这部分testbed框架做了相应的处理,且作为Test类的一部已经完成了。

float32 timeStep = 1/20.0;  
int32 velocityIterations = 8;
int32 positionIterations = 3;

myWorld->Step( timeStep, velocityIterations, position iterations);


在这个例子中,1/20秒调用一次Step方法,所以在场景中的物体如果每秒移动5米,那么每调用Setp一次物体就移动5/20=0.25米。

其中timeStep参数会影响到世界中所有受到重力的物体。你可能发现通过调整时间步长,能够对物体的加速度产生影响。

为了让模拟看起来更逼真,在游戏中通常会将timeStep的值设置成每次调用Step()方法的频率值。比如说testbed中,默认

的帧率为每秒60帧,所以Step()方法也会在一秒内调用60次,并且把timeStep设置成1/60秒。

当物体之间发生碰撞时,速度迭代和位置迭代的设置将会对其产生影响。通常在Box2D中,当两个物体进行碰撞检测时,

物体之间会发生重叠(互相进入),所以需要做一些计算来得出哪个物体应该移动或者旋转,来使它们不再发生重叠。让这两

个数值越大,模拟的精度也就越高,当然了性能消耗也就会越大。



1.3、发现定制器的作用域和切断射线并找到相交的定制器

这个涉及到复杂的世界(world)的计算了,本人目前还不能理解与掌握,暂时不做笔记

2、自定义重力

大家看完上面的物理世界后,有没有这样的想法,演示一个有多个物体在同一水平线上同时下落,设置他们的重力不同来

展那种神奇的效果了?答案是肯定的!!

2.1 为每一个物体指定不同的重力

我们经常会遇到的一个问题是,在其他物体依然遵循重力规则的情况下,如何让指定的物体不受重力影响。其实这实现

起来很简单,现在就用我们所了解的力矩试着实现它。上一篇文章里面我们创建了三个物体,这里我们继续拿来用:

//.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);


我们运行后,会发现他们三个是自然在同一时间落下的,既然在单个时间步长内重力与作用于物体向下的线性力矩类似。

那么我们只需要一个相同的向上的力进行抵消,这样我就实现了不同重力(其实还是同一个重力,只不过我们人为的偷偷的又

多施加了点别的力)。所需力的大小与物体自身的质量有关:

<span style="font-family:SimSun;font-size:18px;">//在Step()函数中添加
m_body[1]->ApplyForce( 0.5f * m_body[1]->GetMass() * -m_world->GetGravity() , m_body[1]->GetWorldCenter());</span><span style="font-family:SimSun;font-size:14px;">
</span>


在新版本(2.2.1以后)可以使用下面的方法直接来改变物体的重力系数

//这样方便许多了,直接把重力缩小成原来的一半
	//直接在这个物体定义的地方添加下面的方法就行了
	if( i == 1 )
	{
		m_body[i]->SetGravityScale(0.5);
	}


采用类似的方法可以对物体施加任何方向上的力,例如你想让物体沿着墙壁或者在天花板上行走。

重要:应该在第一个时间步长之前对物体施加抵消重力的力矩。如果在主循环中的Step()方法之后调用ApplyForce()方法,

那么在第一个时间步长内,在重力被抵消之前物体将会向下移动一点(这个只要自己分别试上面种方法会感觉到的)

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: