引文:http://blog.csdn.net/z104207/article/details/44591197
下一篇
物理引擎很可怕,我真的需要它么?请告诉我不是这样的!
别逃走啊,物理引擎其实也不是个藏在你床下准备把你吓个半死的怪物。或许你的需求很简单,简单到并不需要使用物理引擎。或许节点对象、update()函数、Rect对象、containsPoint()函数或intersectsRect()函数这些就够你用的了。例如:
1
2
3
4
5
6
7
8
9
10
|
void
update(
float
dt)
{
auto p = touch->getLocation();
auto rect =
this
->getBoundingBox();
if
(rect.containsPoint(p))
{
// do something, intersection
}
}
|
上面这套系统能满足简单的需求,但却无法扩展。假如你有100个精灵,而所有的这些精灵都需要不断地更新,以检测与其他对象的重叠状况,那该怎么办呢?用上面的系统,这也是可以实现的,但是会严重消耗CPU的使用率并影响帧速率。你的游戏就没办法继续玩下去了。物理引擎(PhysicsEngine)帮我们解决了这些问题,并且它是可扩展的,还也不会对CPU造成过大压力。这或许看起来有点陌生,我们还是来看一个简单的例子。之后,我们还是来看一个简单的例子,力求将概念、术语以及实践结合起来。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
// create a static PhysicsBody
auto physicsBody = PhysicsBody::createBox(Size(65.0f , 81.0f ), PhysicsMaterial(0.1f, 1.0f, 0.0f));
physicsBody->setDynamic(
false
);
// create a sprite
auto sprite = Sprite::create(
"whiteSprite.png"
);
sprite->setPosition(Vec2(400, 400));
// sprite will use physicsBody
sprite->setPhysicsBody(physicsBody);
//add contact event listener
auto contactListener = EventListenerPhysicsContact::create();
contactListener->onContactBegin = CC_CALLBACK_1(onContactBegin,
this
);
_eventDispatcher->addEventListenerWithSceneGraphPriority(contactListener,
this
);
|
虽然上面这个例子已经很简单了,但你可能还是觉得它复杂得有点吓人?没关系,让我们来更仔细地分析一下它,我们会发现也没那么复杂的。代码中的创建步骤为:创建PhysicsBody对象。创建Sprite精灵。Sprite精灵对象应用PhysicsBody对象的属性。创建了一个监听器以响应onContactBegin事件。
一旦我们一步步地来分析,这些概念都变得容易理解了。理解下面这些术语和概念,会有利于你更好地了解物理引擎的所有细节:
PhysicsBody对象包含了一个对象的物理属性。这些属性包括:质量、位置、自旋度、速度和衰减度。PhysicsBody对象是形状的核心。当你把形状和PhysicsBody关联后,PhysicsBody对象才能具有形状。
材质描述了材料的以下属性:
密度:它被用于计算母体的质量属性。
摩擦:它被用于进行物体间的相对运动。
恢复系数:它被用于使物体反弹。恢复系数一般设为0到1之间。0说明不反弹,1说明完全反弹。
形状描述了碰撞的几何属性。将形状绑定到刚体,就定义了一个刚体的形状。如果必要,你可以为一个刚体关联无数的形状,这是一种定义复杂形状的方式。每个形状都与一个PhysicsMaterial对象相关,并且拥有以下的属性:type(种类), area(面积), mass(质量), moment(转矩), offset(偏移量/重心)和tag(标签)。可能你还对它们中的某些还感到陌生:
type:描述了一系列的形状,例如圆形,矩形,多边形等。
area:用于计算刚体的质量。密度和体积决定了刚体的质量。
mass:刚体所含的物质的量,可以用两种方式进行测量:物体在给定的力下获得的加速度大小,或者在一个引力场中物体受到力的大小。
moment:决定了获得特定角加速度所需要的转矩。
offset:在刚体的当前坐标中,相对于刚体的重心所偏移的量。
tag:用以使开发者较容易地确定形状。你大概还能记得把?你可以为所有的节点都分配一个标签,以进行辨识和实现更容易的访问。
我们这样来描述不同的形状:
PhysicsShape:shapes(形状)实现了PhysicsShape的基类。
PhysicsShapeCircle:圆是实心的。你无法用圆(circle)形状来实现空心圆。
PhysicsShapePolygon:多边形(Polygon)形状是指实心的且外凸的多边形。
PhsicsShapeBox:矩形(Box)形状是外凸的多边形的一种。
PhysicsShapeEdgeSegment:一种线段的形状。
PhysicsShapePolygon:空心多边形。一种由多个线段构成的多边形的边缘。
PhysicsShapeEdgeBox:空心矩形形状。一种由四个线段组成的矩形的边缘。
PhysicsShapeEdgeChain链形形状(chain shape)可以有效地把许多边缘联结起来。
连接(contacts)和关节(joint)对象描述了刚体相互关联的方式。
物理刚体被添加到一个叫世界(World)的容器里,这也是它们被模拟的场所。将bodies,shapes,constraints这些对象添加到物理世界中,将整个物理世界作为一个整体进行更新。物理世界决定了所有这些部件在一起的互动方式。其中,用物理API实现的许多互动都是与PhysicsWorld这个对象有关的。
此处有许多需要记住的东西。请把这些术语记在身边,待会用到的时候以便随时查阅。
物理世界(PhysicsWorld)对象是进行物理模拟时的一个核心部件。物理世界(PhysicsWorld)与场景(Scene)紧密整合在一起。让我们来看一个我们都会涉及到的例子吧。你住的房子里有厨房吗?你想这个问题的时候,就像是在想你的物理世界一样!现在,你的世界里拥有一些物理刚体(PhysicsBody)对象,就跟食物、刀具、电器这些东西一样!在这个世界中,这些刚体相互作用。它们相互接触,并且对相互的接触做出反应。例如:用刀子切开食物,并把它放到电器中。刀子切到食物了吗?可能切到了。也可能还没有。还可能这个刀子根本就不适合做这个。
你可以用下面的方式创建一个包含有PhysicsWorld的Scene对象:
1
|
auto scene = Scene::createWithPhysics(); |
每一个物理世界(PhysicsWorld)都具有与之相关的属性:
-重力(gravity):全局重力,应用于整个物理世界。默认值为Vec2(0.0f,-98.0f)。 -速度(speed):设定了物理世界的速度。这里,速度指的是这个模拟世界运动的一种比率。默认值为1.0。 -刷新率:设定了物理世界的刷新率,这里刷新率指的是EngineUpdateTimes/PhysicsWorldUpdateTimes的比值。 -子步(substeps):设定了物理世界中每次刷新的子步数量。
刷新物理世界的过程也被称为步进(stepping)。按照默认设置,物理世界会不停地进行自动刷新。这被称为“自动步进(auto stepping)”,它会自动地进行。你可以通过设定PhysicsWorld::setAutoStep(false)禁用一个物理世界的auto step,然后通过设定PhysicsWorld::step(time)来手动刷新PhysicsWorld。substeps使用比单一框架更加精确的时间增量来刷新物理世界。使用它,我们可以实现更加细致地实现对步进过程的控制,包括更加流畅的运动。
物理刚体(PhyicsBody)对象具有位置(position)和速度(velocity)两个属性。你可以在PhysicsBody上应用forces、movement、damping和impulses。物理刚体可以是静态的,也可以是动态的。静态的刚体在模拟世界中不会移动,看起来就像它拥有无限大的质量一样。动态的刚体则是一种完全仿真的模拟。它可以被用户手动移动,但更常见的是它们受到力的作用而移动。动态刚体可以与所有的刚体类型发生碰撞。Cocos2d-x提供了Node::setPhysicsbody()来将物理刚体与一个节点对象关联在一起。
让我们来创建一个静态的物理刚体对象和5个动态的物理刚体对象,并且把它们都设为矩形:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
auto physicsBody = PhysicsBody::createBox(Size(65.0f, 81.0f),
PhysicsMaterial(0.1f, 1.0f, 0.0f));
physicsBody->setDynamic(
false
);
//create a sprite
auto sprite = Sprite::create(
"whiteSprite.png"
);
sprite->setPosition(s_centre);
addChild(sprite);
//apply physicsBody to the sprite
sprite->setPhysicsBody(physicsBody);
//add five dynamic bodies
for
(
int
i = 0; i < 5; ++i)
{
physicsBody = PhysicsBody::createBox(Size(65.0f, 81.0f),
PhysicsMaterial(0.1f, 1.0f, 0.0f));
//set the body isn't affected by the physics world's gravitational force
physicsBody->setGravityEnable(
false
);
//set initial velocity of physicsBody
physicsBody->setVelocity(Vec2(cocos2d::random(-500,500),
cocos2d::random(-500,500)));
physicsBody->setTag(DRAG_BODYS_TAG);
sprite = Sprite::create(
"blueSprite.png"
);
sprite->setPosition(Vec2(s_centre.x + cocos2d::random(-300,300),
s_centre.y + cocos2d::random(-300,300)));
sprite->setPhysicsBody(physicsBody);
addChild(sprite);
}
|
结果是,5个动态的物理刚体对象围绕在一个静态的物理刚体对象周围不停地发生碰撞。
下一篇