Box2D C++ 物体与定制器

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


物体与定制器分不家,应该所有的物体都需要定制器,没有定制器物体就失去了意义(这样说是不是有点夸张啊,不要拍板砖)


1、物体



物体是物理场景中的基本对象,但是这里的物体并不是你看到的实际互相弹跳碰撞的实物。听起来很费解吗?挺住!马上做解释!


你可以把物体想象成是一种看不见摸不着的实物的属性。这些不可见的属性是:


-质量(mass)-实物到底有多重 

-速度(velocity)-某方向上实物到底运动多快 

-转动惯量(rotational inertia)-开始或停止转动需要多大的力 

-角速度(angular velocity)-某方向实物转动的速度有多快 

-位置(location)-实物在哪 

-角度(angle)-实物面向哪个方向


即便你知道一个对象的所有这些特性,你仍然不清楚这个对象的长像或者它与其它物体产生碰撞的时候会作出什么样的反应。

那到底我们怎么才能知道这个物体长啥样了?那就需要 定制器 了


2、定制器



定制器用来描述场景中对象的大小,形状,材质属性等。一个物体可以附加多个定制器,

物体的质心会因为定制器的附加顺序所影响。当两个物体相撞时,会根据各自的定制器作出相应的反应。

定制器的主要属性如下:


-形状 - 多边形或圆弧 

-恢复 - 定制器的弹力 

-摩擦 - 光滑程度 

-密度 - 物体大小的重量 


3、物体的属性



在Box2D中有三种类型的物体:静态物体(static),动态物体(dynamic)以及运动学物体(kinematic)。


我们创建动态物体来作为例子分析



3.1 创建物体


代码:

/*********************start*************************/
	//定义一个物体的基本属性,他基本包含了我们所知现实世界物体的所有属性
	b2BodyDef bodyDef;
	//设置一个动态物体
	bodyDef.type = b2_dynamicBody;
	//设置物体出现时的角度 注意在Box2D中都是使用弧度的没有角度
	bodyDef.angle = 0;
	//设置位置
	bodyDef.position.Set(10, 30);

	//创建了一个物体,里面用了指针,那就意味着物体能直接改变他的属性
	b2Body *dynamicBody = m_world->CreateBody(&bodyDef);
	
	//形状
	b2PolygonShape boxShape;
	//创建一个2x2的正方形盒子
	boxShape.SetAsBox(1,1);

	//定制器
	b2FixtureDef fixtureDef;
	fixtureDef.shape = &boxShape;
	//物体的密度
	fixtureDef.density = 10;
	dynamicBody->CreateFixture(&fixtureDef);
	/*************到此就一个正方形动态物体产生了******************/

这里,我们用到了父类Test中类型为b2World类型的成员变量m_world。world类型的对象就像是Box2D中的老大,

它掌管着创建和销毁物理对象。为物体设置大小,形状以及其它更明确的性质,通过为其添加定制器(fixtures)来实现。

此外,即便为物体添加默认的定制器也会影响物体的质量。物体可以附加多个定制器,附加的每一个定制器都会影响物体的总质量。

有人会问这个质量怎么计算的?定制器的质量是通过其自身面积(area)和密度进行相乘来计算的,最终算为物体的质量,这个后面会有讲到的


3.2 设置物体属性


现在,我们设置一些文章开始提到的属性,看看会发生什么。比如说,改变初始位置和角度:

dynamicBody->SetTransform(b2Vec2(-10, 10), 10);
	//这样写是角度为10度
	//#define DEGTORAD 0.0174532925199432957f
	//dynamicBody->SetTransform(b2Vec2(-10, 10), 10*DEGTORAD);

这个是物体的初始位置移到-10,10这个位置,并且角度变为了 10*DEGTORAD (这个DEGTORAD是个宏,过会给出数度)

记住全是变成,而不是变化!!


我们也可以设置物体的线速度和角速度:

	//往左和上的弧线方向移动的线速度
	dynamicBody->SetLinearVelocity(b2Vec2(-10,10));
	//每秒按顺时针方向变化90度
	dynamicBody->SetAngularVelocity(-90 * DEGTORAD);

3.3 物体比较


静态物体:不会移动。即便你像上面那样成功使用setTransform方法改变静态物体的位置,设置静态物体的速度属性,

也不会有任何效果,他就是那么坚强的定在那里。


动态物体:一切正常,就像现实世界中那样


运动学物体:之前看到的动态物体可以移动,但静态物体不能移动。当一个静态物体和动态物体发生碰撞的时候,

静态物体总能“获胜”并坚挺在地面上,动态物体根据实际情况被弹回,两个物体之间不会发生重叠。

运动学物体非常像静态物体,当它与动态物体相撞之后,总能保持自己不动,把动态物体反弹回去,

与静态物体唯一不同的是,运动学物体可以被移动,也就是可以使用类似于SetTransform之类的函数。如果他与静态物体相遇会穿透过去。

下面看两组动态图像就知道了:


往右上移动的是 运动物体,他是直接穿透过静态物体的


可以看到就算是运动物体与动态物体相碰,也不会改变运动方向

在大多数游戏中,动态物体通常被用来创建玩家和其它场景中的角色,静态物体被用来创建墙,地板等等。

运动学物体通常用来扮演那些可以移动或旋转但是不能被动态物体所撞动的物体。

一个比较恰当的例子是横屏游戏中一个移动的平台,该平台可以使用运动学物体来模拟-这可以保证不论玩家如何跳跃,

都不能与之由于相撞而产生位移。


3.4 获取物体属性


很多情况下你都想知道物体目前在哪儿或者移动有多快,旋转角度等等。实现这个很简单,让我们现在就做一个尝试。

为此,我们需要在Step()方法中访问物体变量, Step()函数是父类的一个虚函数,他是每一帧都会被触发的函数,所以

可以在他里面使用 类似geter之类的函数来时时获取当前物体一些属性,比如:速度等

b2Vec2 pos = dynamicBody->GetPosition();
float angle = dynamicBody->GetAngle();
b2Vec2 vel = dynamicBody->GetLinearVelocity();

3.5 遍历世界中的物体


如果你想监视世界中的所有物体,你可以像下面这样做。GetBodyList()方法可以返回物体链表的第一个元素

for ( b2Body* b = m_world->GetBodyList(); b; b = b->GetNext())
{
    //do something with the body 'b'
}


3.6 摧毁


当一个物体完成了它的使命,你可以通过调用世界对象的DestroyBody方法将其移除:

m_world->DestroyBody(dynamicBody);

当像上面这样销毁物体之后,物体所附加的所有定制器(fixtures)和连接器(joins)都会被销毁。记住!当使用这个方法之后不要再调用这个已经删除的物体指针!


4 定制器的属性



其实上面的代码中已经使用了定制器,大家有可能已经提前接触到了定制器的一些用法,下面简单的讲讲


4.1 形状(Shapes)


每个定制器都有形状属性,当定制器在场景中移动的时候,它们之间的碰撞监测会依赖形状属性。

形状属性可以设置成弧形或是多边形。


弧形:

b2CircleShape circleShape;
circleShape.m_p.Set(0, 0); 
circleShape.m_radius = 1; //圆 半径为1


多边形:

使用多边形,你可以独立的设置多边形的每一个顶点坐标来自定义多边形的形状,如果你想要盒子或者直线形状,

我们自定义了一个多边形的顶点:

b2Vec2 vertices[5];
vertices[0].Set(-1,  2);
vertices[1].Set(-1,  0);
vertices[2].Set( 0, -3);
vertices[3].Set( 1,  0);
vertices[4].Set( 1,  1);

b2PolygonShape polygonShape;
polygonShape.Set(vertices, 5); 

如果使用这种方式创建多边形定制器,这里有几个需要注意的事情。首先,默认情况下每个多边形的顶点为8个,如果你想要设置更多的顶点,

需要修改b2Settings.h头文件中的b2_maxPolygonVertices值,顶点必须以逆时针顺序排列,并且组成的是凸多边形。

凸多边形的特点是,如果沿着任意一条边做直线,多边形均在直线的同侧(要么在左侧,要么在右侧)。



4.2 密度(Density)


到目前为止,你可能在纳闷,为什么我用鼠标光标拖拽物体的时候,物体不会像期望中的那样旋转呢?

那是因为我们还没有为定制器设置任何密度值。物体的面积乘以密度然后生成定制器的质量。


4.3 多个定制器(Multiple fixtures)


我们可以把这个三个定制器附加到同一个物体上,而且看起来非常简单,像上面的例子,只要把下面产生的两个定制器全用的同一个

物体上:

	kinematicBody->CreateFixture(&fixtureDef);
	kinematicBody->CreateFixture(&fixtureDef_1);
	kinematicBody->CreateFixture(&fixtureDef_2);


4.4 摩擦(Friction)

当定制器和地面接触的时候,定制器中的摩擦系数会用来计算物体的滑动速度。摩擦系数的大小可以设置在0~1之间,

0意味着完全没有摩擦。当两个物体发生碰撞接触的时候,摩擦碰撞的结果往往是趋向于摩擦系数低的方向运动。

我们要看效果只需要在定制器代码中添加下面一行:


//这里表示没有摩擦
myFixtureDef.friction = 0;


摩擦系数是定制器的独立属性和物体自身无关,摩擦系数为1并不能保证每次都没有滑动出现。



4.5 恢复(Restitution)

恢复衡量了定制器‘弹性’的大小。像摩擦一样,恢复系数的也控制在0~1之间,0意味着定制器根本没有弹性,1意味着无能量损失,全部反弹回来。

当两个定制器之间发生碰撞时,碰撞反弹的方向取决于恢复系数较高的定制器。我们要看效果只需要在定制器代码中添加下面一行:


//恢复系数为0
myFixtureDef.restitution = 0;


恢复系数为0并不总能保证没有反弹,现实中少量的能量会在反弹过程中损耗



4.6 运行中改变定制器属性

有时候在游戏中,你可能希望依赖游戏中的某个事件对定制器的属性进行修改。你可以通过定制器中的setter方法来改变摩擦系数,

密度系数以及恢复系数。因为我们已经有了那个需要改变的定制器的引用,前面说过使用了指针对象来生成物体对象,

那么你可以轻易的只改变定制器,他就能改变物体的动作参数了,像这样进行改变:

//fixture 你的定制器变量
fixture->SetDensity( ... );
fixture->SetRestitution( ... );
fixture->SetFriction( ... );

4.7 遍历与摧毁

同物体一样,他肯定也有遍历和摧毁

遍历:


for (b2Fixture* f = body->GetFixtureList(); f; f = f->GetNext())
{
    //do something with the fixture 'f'
}


摧毁:

dynamicBody->DestroyFixture(myFixture);


因为定制器是作用于物体上的,物体是存在于世界中,所以他的摧毁是由物体来实行,这点需要注意一下

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值